.call()、.apply()、.bind()方法其实效果是一样的,一句话来说就是在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
1) 三者的区别:
apply()方法接收两个参数,( this值,参数数组 )call()方法接收若干个参数 , ( this值 , 参数1 , 参数2 , 参数3 .....)bind()方法接收一个参数,( this值 ),与上面两个不同的是,bind() 方法会创建一个新的函数实例,并将这个新的函数实例内部的 this 值指向 传进去参数!!
2) 其内部的进行操作大致为:
-
- 将该函数设置为指定对象的属性,这样函数内部的this就会指向该对象,就实现了改变函数内部this指向的操作!!!
-
- 执行该函数(注意要把 .call() 中传入的参数传给该函数)
-
- 删除该函数属性
-
- 如果该函数有返回结果,就返回该结果
-
- 如果,.call(null) ,则默认指定对象为 window!!!
3) 所以对 .call() 的模拟实现如下:
Function.prototype.myCall = function(context){
5 var context = context? context : window;
1 context.fn = this; // 因为该函数属性后面还会删除,所以随便起名
2 // 把 .call() 后面的参数传入函数中执行
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args +')');
// 可以使用 ES6 的扩展运算符
// var result = context.fn(...[].slice(1).call(arguments))
3 delete context.fn
4 return result
}
4) 所以对 .apply() 的模拟实现如下:
Function.prototype.apply = function (context, arr) {
var context = Object(context) || window;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
}
else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')')
}
delete context.fn
return result;
}
- 因为 .call() 的参数传递是一个一个传的,而 .apply() 的参数,是以数组的形式传的,所以在模拟实现 .apply() 方法时,就可以直接接收!!!