call、apply 功能介绍
call 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数。
call 和 apply 的区别:传入参数的格式不同,call 正常逐个传入 apply 接受一个参数数组。
注意点:
- 将 this 绑定为指定对象。
- 如果传入 null、undefined 将视为传入 window 对象,如果是其他基本类型将其变为对应的包装对象。
- 执行的函数可以有返回值。
// 用法
var value = 2;
var obj = {
value: 1
}
function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
bar.call(null); // 2
console.log(bar.call2(obj, 'kevin', 18));
// 1
// Object {
// value: 1,
// name: 'kevin',
// age: 18
// }
模拟实现
Function.prototype.call = function (context) {
// 判断是否为 null 或 undefined
if(context === null || context === undefined) {
context = window
} else {
// 将其他基本的数据类型转换为对应的包装对象
context = Object(context)
}
context.fn = this;
var args = [];
// 拿到传入的参数
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
// 因为参数是字符串,所以用 eval 执行一下
var result = eval('context.fn(' + args +')');
// 删除不留痕迹
delete context.fn
// 放回函数执行的结果
return result;
}
同样道理 apply 也差不多
Function.prototype.apply = function (context, arr) {
// 判断是否为 null 或 undefined
if(context === null || context === undefined) {
context = window
} else {
// 将其他基本的数据类型转换为对应的包装对象
context = Object(context)
}
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;
}
参考:
[1] Javascript 深入之 call 和 apply 的模拟实现。
[2] MDN