js call和apply方法
MDN上的介绍是:apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。
call和apply都是为了改变某个函数运行时的上下文而存在的,即为了改变函数体内部this的指向。JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers); // 参数数组
console.log(max); // 7
// call方法:
var max1 = Math.max.call(null, 5, 6, 2, 3, 7);
console.log(max1); // 7
先看语法:
func.apply(thisArg, [argsArray])
第一个参数thisArg, 可选。
即在 func 函数运行时使用的 this 值。在非严格模式下,指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。
第二个参数argsArray,可选。
一个数组或类数组对象。如果该参数的值为 null 或 undefined,则表示不需要传入任何参数。
函数返回值是调用有指定this值和参数的函数的结果。
我们可以模拟实现:
Function.prototype.call2 = function(context) {
var context = Object(context) || window; // 为null或undefined则指向window
// 首先要获取调用call的函数,用this可以获取
context.fn = this;
var result = context.fn(); // 可能会有返回结果
delete context.fn;
return result;
}
但call 方法还可以传参数, 我们先使用es6语法进行模拟:
Function.prototype.call2 = function(context) {
var context = Object(context) || window; // 为null或undefined则指向window
// 首先要获取调用call的函数,用this可以获取
context.fn = this;
var result;
// 判断是否有第二个参数
if(arguments[1]){
result = context.fn(...arguments[1]);
}else {
result = context.fn();
}
delete context.fn;
return result;
}
不使用es6方法的话,我们可以使用eval函数,因为我们需要得到类似这种"obj.fn(args1,args2,args3)" 这样的 ,通过将所有参数拼成字符串然后eval执行
Function.prototype.call2 = function(context) {
var context = Object(context) || window; // 为null或undefined则指向window
// 首先要获取调用call的函数,用this可以获取
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;
}
参考资料: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
https://github.com/mqyqingfeng/Blog/issues/11
https://segmentfault.com/q/1010000009688328