###
本篇文章记录了一下实现bind、call、apply三个方法的方式。
call的基本使用 var ary = [12 , 23 , 34 ];ary.slice();
以上两行简单的代码的执行过程为:ary
这个实例通过原型链的查找机制找到Array.prototype
上的slice
方法,让找到的slice
方法执行,在执行slice
方法的过程中才把ary
数组进行了截取。
注意 :slice
方法执行之前有一个在原型上查找的过程(当前实例中没有找到,再根据原型链查找)。
当知道了一个对象调用方法会有一个查找过程之后,我们再看:
var obj = {name :'iceman' };function fn ( ) { console .log(this ); console .log(this .name); } fn(); fn.call(obj);
call方法的作用 :首先寻找call
方法,最后通过原型链在Function
的原型中找到call
方法,然后让call
方法执行,在执行call
方法的时候,让fn
方法中的this
变为第一个参数值obj
,最后再把fn
这个函数执行。
知道这个原型上的原理后,咱们就可以动手分析实现这三个方法了。
bind、call、apply 区别
call
和 apply
都是为了解决改变 this
的指向。作用都是相同的,只是传参的方式不同。
除了第一个参数外,call
可以接收一个参数列表,apply
只接受一个参数数组
let a = { value: 1 } function getValue (name, age ) { console .log(name) console .log(age) console .log(this .value) } getValue.call(a, 'yck' , '24' ) getValue.apply(a, ['yck' , '24' ])
bind
和其他两个方法作用也是一致的,只是该方法会返回一个函数。并且我们可以通过 bind
实现柯里化
如何实现一个 bind 函数 对于实现以下几个函数,可以从几个方面思考
不传入第一个参数,那么默认为 window
改变了 this
指向,让新的对象可以执行该函数。那么思路是否可以变成给新的对象添加一个函数,然后在执行完以后删除?
当然是肯定的,于是我们可以这样写:
Function .prototype.myBind = function (context ) { if (typeof this !== 'function' ) { throw new TypeError ('Error' ) } var _this = this var args = [...arguments].slice(1 ) return function F ( ) { if (this instanceof F) { return new _this(...args, ...arguments) } return _this.apply(context, args.concat(...arguments)) } }
如何实现一个 call 函数 Function .prototype.myCall = function (context,...arg ) { var context = context || window let symbol = new Symbol (); context[symbol] = this ; let result = context[symbol](...arg) delete context[symbol] return result }
如何实现一个apply 函数 apply实现原理与call实现基本类似,只有传值的方式不一样。
Function .prototype.myApply = function (context,arg ) { var context = context || window let symbol = new Symbol (); context[symbol] = this ; let result = context[symbol](arg) delete context[symbol] return result }
经过对以上的函数进行检测 , 完美通过。
const obj = { name : 'xiaoxiao' , getName : function (arg ) { console .log(`我是${this .name} 里面的,我里面有${arg} ` ); } } obj.getName([0 ,0 ,0 ,0 ,0 ]); const obj2 = { name : 'huahua' } obj.getName.myCall(obj2,1 ,1 ,1 ,1 ,1 ,1 ); obj.getName.myBind(obj2)(2 ,2 ,2 ,2 ,2 ,2 ); obj.getName.myApply(obj2,[3 ,3 ,3 ,3 ,3 ,3 ]);