观感度:????????????????????
口味:蟹黄豆腐
烹饪工夫:5min
本文已收录在前端食堂同名仓库Github
github.com/Geekhyt,欢迎光临食堂,如果感觉酒菜还算可口,赏个 Star 对食堂老板来说是莫大的激励。
从略带银丝的头发和干净利落的步调我察觉到,背后坐着的这个面试官有点深不可测。我像平常一样,筹备花 3 分钟的工夫给面试官来一套昨天晚上精心筹备的自我介绍。我自信且得意的诉说着对过往我的项目所付出的心血,所做的优化获得了怎么的成绩,为公司进步了多少的支出。。。
显然,面试官对我说的数字很感兴趣,嘴角微微上扬,通过了一番细节的探讨和技术的对线后。面试官拿出了一张纸。
手写代码。
重视根底的面试官是靠谱的,为了驯服他,我一边解说着实现原理一边写出了代码。
手写 call
call 和 apply 的区别:call 办法接管的是一个参数列表,apply 办法接管的是一个蕴含多个参数的数组。
- 1.
context
存在就应用context
,否则是window
- 2.应用
Object(context)
将context
转换成对象,并通过context.fn
将this
指向context
- 3.循环参数,留神从
1
开始,第0
个是上下文,前面才是咱们须要的参数 - 4.将参数字符串
push
进args
- 5.字符串和数组拼接时,数组会调用
toString
办法,这样能够实现将参数一个个传入,并通过eval
执行 - 6.拿到后果返回前,删除掉
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
- 1.
apply
无需循环参数列表,传入的args
就是数组 - 2.然而
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
- 1.
bind
的参数能够在绑定和调用的时候分两次传入 - 2.
bindArgs
是绑定时除了第一个参数以外传入的参数,args
是调用时候传入的参数,将二者拼接后一起传入 - 3.如果应用
new
运算符结构绑定函数,则会扭转this
指向,this
指向以后的实例 - 4.通过
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;}
手写 new
- 1.
Constructor
就是new
时传入的第一个参数,残余的arguments
是其余的参数 - 2.应用
obj.__proto__ = Constructor.prototype
继承原型上的办法 - 3.将残余的
arguments
传给Contructor
,绑定this
指向为obj
,并执行 - 4.如果构造函数返回的是援用类型,间接返回该援用类型,否则返回
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;}
手写 instanceOf
- 1.在
left
的原型链中层层查找,是否有原型等于prototype
- 2.确定边界条件,如果
left === null
,即找到头没找到返回false
,right === left
,即找到返回true
- 3.
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__; }}
手写 Object.create
- 新建一个空的构造函数
F
,而后让F.prototype
指向obj
,最初返回F
的实例
const myCreate = function (obj) { function F() {}; F.prototype = obj; return new F();}