1. call
call用于指定函数调用时候上下文对象this,比如
var a = 9;
const obj = {
a: 2,
show: function() {
console.info(this.a);
}
};
obj.show(); //2
const other = {
a: 99
};
obj.show.call(other); //99
利用对象直接调用其函数的时候,该函数的this指向该对象,
Function.prototype.call2 = function(context, ...args) {
context.prop = this; //将 call2的调用者 object.show 赋值给给上下文对象
context.prop(...args); // 通过上下文对象调用被call的函数
delete context.prop; // 不能改变context对象,所以调用完 要删除额外属性
};
obj.show(78); //2
obj.show.call2(other, 34); //99
但是这种写法扩展操作符是ES6的,所以可以改进,prop属性可能跟context已有的属性冲突,所以可以用symbol去改进,
- 函数可能有返回值,改进如下
Function.prototype.call2 = function(context, ...args) {
context.prop = this; //将 call2的调用者 object.show 赋值给给上下文对象
const ret = context.prop(...args); // 通过上下文对象调用被call的函数
delete context.prop; // 不能改变context对象,所以调用完 要删除额外属性
return ret; // 在此返回函数执行结果
};
var a = 9;
const obj = {
a: 2,
show: function() {
console.info(this.a);
return this.a + 1;
}
};
const other = {
a: 99
};
const ret = obj.show(78); //2
console.info(ret); // 3
const result = obj.show.call2(other, 34); //99
console.info(result); // 100
-
用ES6的扩展运算符去模拟ES5代码不合适吧,继续改进
利用eval函数执行js字符串
Function.prototype.call2 = function() {
var args = [];
var context = arguments[0];
for (let i = 1; i < arguments.length; i++) {
args.push(arguments[i]);
}
context.prop = this; //将 call2的调用者 object.show 赋值给给上下文对象
var str = "context.prop(";
str += args.join(",") + ")";
var ret = eval(str); //使用eval执行拼接好的函数调用字符串
delete context.prop; // 不能改变context对象,所以调用完 要删除额外属性
return ret;
};
var a = 9;
const obj = {
a: 2,
show: function(x) {
console.info(this.a, x);
return this.a + 1;
}
};
const other = {
a: 99
};
const ret = obj.show(78); //2 78
console.info(ret); // 3
const result = obj.show.call2(other, 34); //99 34
console.info(result); // 100
2. apply
apply 的第二个参数是数组或者类数组
var a = 9;
const obj = {
a: 2,
show: function(age, name, sex) {
console.info(this.a, age, name, sex);
}
};
obj.show(34, 'geek', 'male'); //2
const other = {
a: 99
};
obj.show.call(other, 25, 'bill', 'jin'); //99
obj.show.apply(other, [25, 'bill', 'jin']); //99
上面的测试得到如下的结果
2 34 'geek' 'male'
99 25 'bill' 'jin'
99 25 'bill' 'jin'
说明在模拟apply的时候需要将apply的第二个参数展开给调用apply的函数
Function.prototype.apply2 = function(context, args) {
context.prop = this;
context.prop(...args);// 需要展开
delete context.prop;
};
obj.show.apply2(other, [9, 8, 7]);
网友评论