call的特点
1.可以改变当前函数的this指向
2.可以让函数执行
例子:
function fn1() {
console.log(1, this);
}
function fn2() {
console.log(2);
}
// fn1.call(fn2); // 1
fn1.call.call(fn2); // 2
// 为什么一个call的时候 打印出来的是1 多个call的时候 打印出来的是2呢
// 可以把call看成
Function.prototype.call = function () {
this();
};
// 多个call的时候 从第1个call开始就看成
call = function () {
this();
};
call.call(fn2);
原理实现:
Function.prototype.call = function (context) {
// call是可以这样用的fn.call.call.call 如果调用的时候没传上下文,则context是window
context = context ? Object(context) : window;
context.fn = this; // 给context添加一个属性,待会儿要让它执行
// call可以传多个参数 fn.call(obj1,1,2,3,4) 除第一个参数是要改变this的引用之外,剩下的都将作为参数
let args = [];
for (let i = 1; i < arguments.length; i++) {
args.push(`arguments[${i}]`);
}
// 利用数组的toString特性 args会以逗号的形式展开 作为fn的参数
let r = eval(`context.fn(${args})`);
delete context.fn;
return r;
};
apply的特点
1.与call原理类似,只是call的参数是多个,apply的参数是数组
Function.prototype.apply = function (context, args) {
context = context ? Object(context) : window;
context.fn = this;
if (!args) return context.fn();
let r = eval(`context.fn(${args})`);
delete context.fn;
return r;
};