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 = context === null || context === undefined ? window: Object(context) ; // 为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 = context === null || context === undefined ? window: Object(context) ; // 为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 = context === null || context === undefined ? window: Object(context) ;  // 为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

猜你喜欢

转载自blog.csdn.net/zxl1990_ok/article/details/88880959