美文网首页
模拟call和apply函数实现

模拟call和apply函数实现

作者: _章鱼小丸子 | 来源:发表于2019-05-15 18:31 被阅读0次

call函数的使用方式如下:

var obj = {
    value: 1
};

function foo(name, age) {
    console.log(this.value);
    console.log(name);
    console.log(age);
}

foo.call(obj, 'aaa', 12); // 1  aaa  12

首先我们要知道call函数都有哪些功能:
1. 改变了this的指向,让它指向obj
2. 函数foo执行
3. 允许传入参数,且参数个数不确定
4. 允许第一个参数context为null
5. 执行后的返回值为函数执行后的返回值

如何实现this指向obj呢,参考对象内部函数定义,如果fn是obj的方法属性,那么就this就指向了obj,然后执行函数,之后再删除函数,这就实现了前两步。

Function.prototype.call2 = function (context){
    context.fn = this;
    context.fn();
    delete context.fn;
}

如何允许传入参数,用到arguments,要将参数一个个传入context.fn,只能动态拼接执行,考虑用eval,eval能将string字符串作为js执行的函数。

Function.prototype.call2 = function (context){
    context.fn = this;
    var args = [];
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }
    eval( 'context.fn(' + args + ')' );
    delete context.fn;
}

如何允许第一个参数可以为null,验证context是否存在,context默认为window对象。即 context = context || window

如何允许有返回值,将函数的执行结果用result变量存储,返回result即可。最终代码如下:

Function.prototype.call2 = function (context){
    context = context || window;
    context.fn = this;
    var args = [];
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }
    const result = eval('context.fn('+ args + ')');
    delete context.fn
    return result
}
const fn = function(name, age) {
    console.log(this.value);
    return {
        name: name,
        age: age
    };
}
const obj = {
    value: 'obj'
}
var value = 'window';
fn.call(null); //'window'

const result = fn.call2(obj, '小明', 12); // 'obj'
console.log(result.age); //12

apply函数的功能和call基本一致,区别在于只有两个参数,第一个参数是context,第二个是函数参数数组。实现和call一致,实现代码如下:

Function.prototype.apply = function(context, arr) {
    var ctx = context || window;
    ctx.fn = this;
    var result;
    if (!arr) {
        result = ctx.fn();
    } else {
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('ctx.fn(' + args + ')');
    }
    delete ctx.fn;
    return result;
};

相关文章

网友评论

      本文标题:模拟call和apply函数实现

      本文链接:https://www.haomeiwen.com/subject/wwdmaqtx.html