根据 Function.prototype.call() - JavaScript | MDN 的定义
call()
方法使用一个指定的this
值和单独给出的一个或多个参数来调用一个函数。
前言
此篇文章仅讨论 更改普通函数内部 this 的引用
,为了简化问题 不区分
严格模式/null/undefined
默认目标类型就是 object
,不讨论其他类型
更改函数this的几种方法
函数直接赋值到目标对象
Function.prototype.call2 = function (context, ...args) {
let uniqueKey = Symbol("全局唯一引用");
context[uniqueKey] = this;
let result = context[uniqueKey](...args);
delete context[uniqueKey];
return result;
};
缺点:如果对象被 冻结
或者 是 Proxy
,函数会赋值失败,而且破坏了原来对象的结构
function test(){
return this.a+this.b
}
ob1 = {a:1,b:2}
调用例子
// 例子1
Object.seal(ob1)
test.call2(ob1)
// 例子2
Object.freeze(ob1)
test.call2(ob1)
// 例子3
ob1 = new Proxy(ob1, {
set(target, key, value) {}
});
test.call2(ob1)
都会得到如下错误:
VM86:4 Uncaught TypeError: context[uniqueKey] is not a function
at Function.call2 (<anonymous>:4:34)
at <anonymous>:1:6
借助原型链更改this
Function.prototype.call3 = function (context, ...args) {
const obj = Object.create(context);
let uniqueKey = Symbol("全局唯一引用");
obj[uniqueKey] = this;
return context[uniqueKey](...args);
};
此方法可以解决对象被冻结/属性拦截的问题 ,但是调用对象已经不是原来的对象
如果有对原型的操作,会发生未期望行为
总结
Function.prototype.call 是 native code
纯 js 无法实现 完整的 Function.prototype.call