Function.call深入
var ary = [12, 23, 34]
ary.slice
ary这个实例通过原型链的查找机制找到Array.prototype上的slice方法
ary.slice() 让找的slice方法执行, 在执行slice方法的过程中, 才把ary数组进行了截取
Funciton.call用法
call方法:
首先让原型上的call方法执行, 在执行call方法的时候, 让fn方法中的this变为第一个参数值obj, 然后再把fn这个函数执行
call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔,直接放到后面
Function.prototype.call = function(){}
var obj = {name: 'lemon'}
function fn(){
console.log(this);
}
fn();
obj.fn();
fn.call(obj);
-> window
->Uncaught TypeError: obj.fn is not a funciton
->{name: 'lemon'}
模拟一个call方法
- 让fn中的this关键字变为context的值 obj
- 让fn方法执行
Function.prototype.myCall = function (context, ...args) {
context = context || window;
context.__proto__.fn = this;
const result = context.fn(...args);
// 执行fn时上下文context已被修改,不是我们所期望的call
delete context.__proto__.fn;
return result;
}
fn.myCall(obj)
一道练习题
function fn1(){
console.log(1);
}
function fn2(){
console.log(2);
}
fn1.call.call(fn2)
->2
先执行fn1.call.call(fn2)
通过fn1的原型链找到call函数
通过找到call函数的原型链找到call
执行call.call(fn2), -> 2
- 前面的一串 fn.call.call.call.call 并没有调用,只是获取对象的call属性,所以,这一串的结果是 Function.call 属性。
- 所以那一串 就是 Function.call.call(fn2);还可以解理为 fn3.call(fn2)。
- 根据call的原理(可参考上面的call模拟),在 fn3执行call,其实际是这样执行的 fn2.fn3()。
- 由于 fn3实际上就是 call 函数,所以, fn2.fn3() 等价于 fn2.call()。
- 所以,上面那一串代码的最终结果,就是调用 fn2,所以结果输出 22.
概括性总结:
不怎么理解的话也可以记住这个概括性诀窍:
碰到两个及两个以上的call都是让第一个参数执行,第一个参数必须是函数;
第二个参数是改变第一个参数中this;
第三个及第三个以后的参数作为实参传给第一个参数。