本文收录了一些在Web前端开发面试中经常会遇到的面试题及答案,希望对大家有所帮助,若有所疏漏欢迎指正。
问题:模拟new
解析:new操作符做了这些事:
它创建了个全新的对象
它会被执行[[Prototype]](也就是proto)链接
它使this指向新创建的对象
通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上
如果函数没有返回对象类型Object(包含Functoin,Array,Date,RegExg,Error),那么new表达式中的函数调用将返回该对象引用
//objectFactory(name,cxk,18)
functionobjectFactory(){
constobj=newObject();
constConstructor=[].shift.call(arguments);
obj.proto=Constructor.prototype;
constret=Constructor.apply(obj,arguments);
returntypeofret===object?ret:obj;
}
问题:实现instanceOf
解析://模拟instanceof
functioninstance_of(L,R){
//L表示左表达式,R表示右表达式
varO=R.prototype;//取R的显示原型
L=L.proto;//取L的隐式原型
while(true){
if(L===null)returnfalse;
if(O===L)
//这重点:当O严格等于L时,返回true
returntrue;
L=L.proto;
}
}
问题:实现Event(eventbus)
解析:eventbus既是node中各个模块的基石,又是前端组件通信的依赖手段之,同时涉及了订阅-发布设计模式,是非常重要的基础。
简单版:
classEventEmeitter
{constructor(){
this._events=this._events
newMap();//储存事件/回调键值对
this._maxListeners=this._maxListeners
10;//设立监听上限
}
}
//触发名为type的事件
EventEmeitter.prototype.emit=function(type,...args)
{lethandler;
//从储存事件键值对的this._events中获取对应事件回调函数
handler=this._events.get(type);
if(args.length0){
handler.apply(this,args);
}else
{handler.call(this);
}
returntrue;
};
//监听名为type的事件
EventEmeitter.prototype.addListener=function(type,fn){
//将type事件以及对应的fn函数放入this._events中储存
if(!this._events.get(type))
{this._events.set(type,fn);
}
};
试版:
classEventEmeitter
{constructor(){
this._events=this._events
newMap();//储存事件/回调键值对
this._maxListeners=this._maxListeners
10;//设立监听上限
}
}
//触发名为type的事件
EventEmeitter.prototype.emit=function(type,...args)
{lethandler;
//从储存事件键值对的this._events中获取对应事件回调函数
handler=this._events.get(type);
if(args.length0){
handler.apply(this,args);
}else
{handler.call(this);
}
returntrue;
};
//监听名为type的事件
EventEmeitter.prototype.addListener=function(type,fn){
//将type事件以及对应的fn函数放入this._events中储存
if(!this._events.get(type))
{this._events.set(type,fn);
}
};
//触发名为type的事件
EventEmeitter.prototype.emit=function(type,...args)
{lethandler;
handler=this._events.get(type);
if(Array.isArray(handler)){
//如果是个数组说明有多个监听者,需要依次此触发里面的函数
for(leti=0;ihandler.length;i++)
{if(args.length0){
handler.apply(this,args);
}else
{handler.call(this);
}
}
}else{
//单个函数的情况我们直接触发即可
if(args.length0)
{handler.apply(this,args);
}else
{handler.call(this);
}
}
returntrue;
};
//监听名为type的事件
EventEmeitter.prototype.addListener=function(type,fn){
consthandler=this._events.get(type);//获取对应事件名称的函数清单
if(!handler)
{this._events.set(type,fn);
}elseif(handlertypeofhandler===function){
//如果handler是函数说明只有个监听者
this._events.set(type,[handler,fn]);//多个监听者我们需要数组储存
}else{
handler.push(fn);//已经有多个监听者,那么直接往数组里push函数即可
}
};
EventEmeitter.prototype.removeListener=function(type,fn)
{consthandler=this._events.get(type);//获取对应事件名称的函数清单
//如果是函数,说明只被监听了次
if(handlertypeofhandler===function)
{this._events.delete(type,fn);
}else{
letpostion;
//如果handler是数组,说明被监听多次要找到对应的函数
for(leti=0;ihandler.length;i++)
{if(handler===fn){
postion=i;
}else
{postion=-
1;
}
}
//如果找到匹配的函数,从数组中清除
if(postion!==-1){
//找到数组对应的位置,直接清除此回调
handler.splice(postion,1);
//如果清除后只有个函数,那么取消数组,以函数形式保存
if(handler.length===1)
{this._events.set(type,
handler[0]);
}
}else
{return
this;
}
}