作用:这三个方法都是用来改变this指向
不同点:
- call和apply 是立即执行函数,但是bind会返回一个改变了this指向的函数,手动执行。
- call和bind的接受参数方式是一个个参数,apply接受参数是一个数组。
作用相同为什么搞了三个方法?不同场景应用方式不同
以下代码可以看出三种方法的使用不同
let obj = {
name: this.name,
objAge: this.age,
myLove: function (fm, t) {
console.log(this.name + "年龄" + this.age, "来自" + fm + "去往" + t); },
};
let obj1 = { name: "huang", age: 22, };
obj.myLove.call(obj1, "达州", "成都"); //huang年龄22来自达州去往成都
obj.myLove.apply(obj1, ["达州", "成都"]); //huang年龄22来自达州去往成 obj.myLove.bind(obj1, "达州", "成都")(); // huang年龄22来自达州去往成都
重写call方法
var context = context || window;
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args +')');
delete context.fn
return result;
}
// 一般面试选这种方式就行,
Function.prototype.myCall1 = function(context, ...args) {
context = context || window;
const key = Symbol('key');
context[key] = this;
const result = context[key](...args);
return result
}
重写apply方法
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;
}
// 第二种方式
Function.prototype.myApply = function(context, args) {
context = context || window;
const key = Symbol('key');
context[key] = this;
const result = context[key](...args);
return result
}
重写bind方法
Function.prototype.myBind = function(context, ...bindArgs) {
// 1. 保存原始函数引用
const originalFunc = this;
// 2. 创建绑定函数(最终返回的函数)
const boundFunc = function(...callArgs) {
// 3. 检测是否通过 new 调用
const isNewCall = this instanceof boundFunc;
// 4. 确定执行上下文
const thisContext = isNewCall ? this : (context || window);
// 5. 合并参数(预置参数 + 调用时参数)
const finalArgs = bindArgs.concat(callArgs);
// 6. 执行原函数并返回结果
return originalFunc.apply(thisContext, finalArgs);
};
// 7. 维护原型链(处理 new 操作符)
if (originalFunc.prototype) {
const EmptyFunc = function() {};
EmptyFunc.prototype = originalFunc.prototype;
boundFunc.prototype = new EmptyFunc();
}
// 8. 返回绑定函数
return boundFunc;
};
```