js apply call模拟

33 篇文章 0 订阅
var name='window上的name'
var obj ={
  name: "obj上的name",
  getName: function(i){
    console.log(this.name, i);
  }
}

var obj2 = {
  name: "obj2上的name"
}
1 绑定上下文
Function.prototype.myApply=function(context){
    // 获取调用`myApply`的函数本身,用this获取
    context.fn = this;
  
    // 执行这个函数
    context.fn();
  
    // 从上下文中删除函数引用
    delete context.fn;
}

obj.getName(); // obj上的name undefined
obj.getName.myApply(obj2); // obj2上的name undefined
2 给定参数
Function.prototype.myApply=function(context){
    // 获取调用`myApply`的函数本身,用this获取
    context.fn = this;
  
    //获取传入的数组参数
    var args = arguments[1];
    //没有传入参数直接执行
    if (args == undefined) { 
        // 执行这个函数
        context.fn()
    } else {
        // 执行这个函数
    context.fn(...args);
    }
  
    // 从上下文中删除函数引用
    delete context.fn;
}

obj.getName(1); // obj上的name 1
obj.getName.myApply(obj2, [2]); // obj2上的name 2

上面用到了es6的扩展元素运算符
下面是不用扩展运算符,使用eval 方法拼成一个函数
eval('context.fn(' + args +')')
args 会自动调用 Array.toString() 这个方法

Function.prototype.myApply=function(context){
    // 获取调用`myApply`的函数本身,用this获取
    context.fn = this;
  
    //获取传入的数组参数
    if (!arguments[1]) {
        // 执行这个函数
        context.fn();
    }
    else {
        var args = [];
        for(var i = 0, len = arguments[1].length; i < len; i++) {
            args.push('arguments[1][' + i + ']');
        }
        // 执行这个函数
        eval('context.fn(' + args +')');
    }
  
    // 从上下文中删除函数引用
    delete context.fn;
}

obj.getName(1); // obj上的name 1
obj.getName.myApply(obj2, [2]); // obj2上的name 2

或者

Function.prototype.myApply=function(context, arr){
    // 获取调用`myApply`的函数本身,用this获取
    context.fn = this;
  
    //获取传入的数组参数
    if (!arr) {
        // 执行这个函数
        context.fn();
    }
    else {
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push('arr[' + i + ']');
        }
        // 执行这个函数
        eval('context.fn(' + args +')');
    }
  
    // 从上下文中删除函数引用
    delete context.fn;
}
3 当传入apply的this为null或者为空时,或函数具有返回值
Function.prototype.myApply=function(context){
    // 获取调用`myApply`的函数本身,用this获取,如果context不存在,则为window
    var context = context || window;
    context.fn = this;
    
    var r;
    //获取传入的数组参数
    if (!arguments[1]) {
        // 执行这个函数
        r = context.fn();
    }
    else {
        var args = [];
        for(var i = 0, len = arguments[1].length; i < len; i++) {
            args.push('arguments[1][' + i + ']');
        }
        // 执行这个函数
        r = eval('context.fn(' + args +')');
    }
  
    // 从上下文中删除函数引用
    delete context.fn;
    return r;
}
obj.getName(1); // obj上的name 1 
obj.getName.myApply(null, [2]); // window上的name 2 
4 call模拟
Function.prototype.myCall=function(context){
    // 获取调用`myApply`的函数本身,用this获取,如果context不存在,则为window
    var context = context || window;
    context.fn = this;
    
    var r;
    //获取传入的数组参数
    var args = [];
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }
    // 执行这个函数
    r = eval('context.fn(' + args +')');
  
    // 从上下文中删除函数引用
    delete context.fn;
    return r;
}

注意:arguments从1开始遍历

参考:https://github.com/axuebin/articles/issues/7
https://github.com/mqyqingfeng/Blog/issues/11

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值