读大佬 @冴羽 JavaScript深入系列juejin.cn/post/684490… 有感
call
call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
var foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar(); // undefined
bar.call(foo); // 1
由上面代码可见,call改变了this的指向。
模拟实现第一版
var foo = {
value: 1,
bar: function() {
console.log(this.value)
}
};
foo.bar(); // 1
delete foo.bar;
这样,this就指向foo了。
以上可总结为
// 第一步:将函数变为对象属性
foo.fn = bar
// 第二步:执行函数
foo.fn()
// 第三步:删除函数属性
delete foo.fn
第一版成品
Function.prototype.call2 = function(context) {
context.fun = this;
context.fun();
delete context.fun;
}
let obj = {
value: 10
}
function bar(){
console.log(this.value)
}
bar.call2(obj) // 10
模拟实现第二版
call 函数给定参数执行函数
var foo = {
value: 1
};
function bar(name, age) {
console.log(name)
console.log(age)
console.log(this.value);
}
bar.call(foo, 'kevin', 18);
// kevin
// 18
// 1
Function.prototype.call2 = function(context) {
if(!context){
// 若参数为null,则this指向window
context = window
}else if(typeof(context)!="object") {
// 如果不是对象的话,则将其转成对象
context = Object(context)
}
context.fun = this;
// 将参数放入一个数组中,需要排除第一个参数
let arr = [];
for(let i = 1; i < arguments.length; i++){
arr.push(arguments[i])
}
// 使用展开语法,将数组展开成函数的参数
let result = context.fun(...arr);
delete context.fun;
// 函数的返回值
return result
}
// 测试
var value = 2;
let obj = {
value: 10
}
function bar(name, age) {
console.log(name)
console.log(age)
console.log(this.value);
}
function bar1(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
bar.call(null); // 2
console.log(bar1.call2(obj, 'kevin', 18));
// 1
// Object {
// value: 1,
// name: 'kevin',
// age: 18
// }
bar.call2(foo, 'kevin', 18);
// kevin
// 18
// 1
apply
apply与call的区别只是传入的参数不同,但是第一个参数还是相同的。
Function.prototype.apply2 = function(context, args) {
if(!context){
// 若参数为null,则this指向window
context = window
}else if(typeof(context)!="object") {
// 如果不是对象的话,则将其转成对象
context = Object(context)
}
args = args || [];
context.fun = this;
// 使用展开语法,将数组展开成函数的参数
let result = context.fun(...args);
delete context.fun;
// 函数的返回值
return result
}