01 call
call是js最好用的函数之一,改变函数上下文是插件编写最经常使用的特性。
var name = "小钢炮";
var cat = {
name: "猫"
}
function say(name) {
console.log(this.name + "-" + name);
};
say("ketty"); // 小钢炮-ketty
say.call(cat, "ketty"); // 猫-ketty
02 实现思路
看下面代码:
function say(name) {
console.log(this.name + "-" + name);
};
var cat = {
name: "猫",
fn: say
};
cat.fn("ketty");
delete cat.fn;
我们把say方法挂载到cat对象上,次数运行say方法的上下文即为cat,执行完之后,过河拆桥的把say方法删除。
03 代码实现
看下面代码:
Function.prototype.callx = function() {
// 第一个参数为上下文
var context = arguments[0];
// 存储要传递的参数
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push("arguments[" + i + "]");
};
// 动态生成一个函数名称
var tempFn = "callfn" + new Date().getTime();
// 将函数挂载到执行环境上
context[tempFn] = this;
// 这里是为了动态传参,类似于es6的context[tempFn](...arr);
eval("context[tempFn](" + args + ")");
delete context[tempFn];
};
say.callx(cat, 'ketty');
console.log(cat);
04 缺陷
-
Object.freeze
由于依赖修改执行环境,所以当目标对象使用Object.freeze时,将无法工作。解决这个问题,并不困难,我们只要将目标对象拷贝一份即可。 -
eval
这里为了动态传参使用了,调用了js引擎,在严格模式下是有问题的。