观感度:🌟🌟🌟🌟🌟前端
口味:蟹黄豆腐git
烹饪时间:5mingithub
本文已收录在前端食堂同名仓库
Github
github.com/Geekhyt,欢迎光临食堂,若是以为酒菜还算可口,赏个 Star 对食堂老板来讲是莫大的鼓励。
从略带银丝的头发和干净利落的步伐我察觉到,面前坐着的这个面试官有点深不可测。我像往常同样,准备花 3 分钟的时间给面试官来一套昨天晚上精心准备的自我介绍。我自信且得意的诉说着对过往项目所付出的心血,所作的优化取得了怎样的成果,为公司提升了多少的收入。。。面试
显然,面试官对我说的数字很感兴趣,嘴角微微上扬,通过了一番细节的探讨和技术的对线后。面试官拿出了一张纸。数组
手写代码。app
注重基础的面试官是靠谱的,为了征服他,我一边讲解着实现原理一边写出了代码。函数
call 和 apply 的区别:call 方法接收的是一个参数列表,apply 方法接收的是一个包含多个参数的数组。
优化
context
存在就使用 context
,不然是 window
Object(context)
将 context
转换成对象,并经过 context.fn
将 this
指向 context
1
开始,第 0
个是上下文,后面才是咱们须要的参数push
进 args
toString
方法,这样能够实现将参数一个个传入,并经过 eval
执行fn
Function.prototype.call = function(context) { context = context ? Object(context) : window; context.fn = this; let args = []; for (let i = 1; i < arguments.length; i++) { args.push('arguments['+ i +']'); } let res = eval('context.fn('+ args +')'); delete context.fn; return res; }
apply
无需循环参数列表,传入的 args
就是数组args
是可选参数,若是不传入的话,直接执行Function.prototype.apply = function(context, args) { context = context ? Object(context) : window; context.fn = this; if (!args) { return context.fn(); } let res = eval('context.fn('+ args +')'); delete context.fn; return res; }
bind
的参数能够在绑定和调用的时候分两次传入bindArgs
是绑定时除了第一个参数之外传入的参数,args
是调用时候传入的参数,将两者拼接后一块儿传入new
运算符构造绑定函数,则会改变 this
指向,this
指向当前的实例Fn
连接原型,这样 fBound
就能够经过原型链访问父类 Fn
的属性Function.prototype.bind = function(context) { let that = this; let bindArgs = Array.prototype.slice.call(arguments, 1); function Fn () {}; function fBound(params) { let args = Array.prototype.slice.call(arguments) ; return that.apply(this instanceof fBound ? this : context, bindArgs.concat(args)); } Fn.prototype = this.prototype; fBound.prototype = new Fn(); return fBound; }
Constructor
就是 new
时传入的第一个参数,剩余的 arguments
是其余的参数obj.__proto__ = Constructor.prototype
继承原型上的方法arguments
传给 Contructor
,绑定 this
指向为 obj
,并执行obj
const myNew = function() { let Constructor = Array.prototype.shift.call(arguments); let obj = {}; obj.__proto__ = Constructor.prototype; let res = Constructor.apply(obj, arguments); return res instanceof Object ? res : obj; }
left
的原型链中层层查找,是否有原型等于 prototype
left === null
,即找到头没找到返回 false
,right === left
,即找到返回 true
left = left.__proto__
,不停的向上查找const myInstanceof = function(left, right) { right = right.prototype; left = left.__proto__; while (true) { if (left === null) { return false; } if (right === left) { return true; } left = left.__proto__; } }
F
,而后让 F.prototype
指向 obj
,最后返回 F
的实例const myCreate = function (obj) { function F() {}; F.prototype = obj; return new F(); }