侧边栏

JavaScript Call函数原理

call原理分析,一定要看最后的例子。

1.call使用例子

function add(c, d) {
  return this.a + this.b + c + d;
}

const obj = { a: 1, b: 2 };

console.error(add.call(obj, 3, 4)); // 10

2.其实现原理类似于下面代码

const obj = {
  a: 1,
  b: 2,
  add: function(c, d) {
    return this.a + this.b + c + d
  }
};
console.log(obj.add(3,4)); //10

其步骤伪码

// 1. 将函数设为对象的属性
 obj.fn = add
// 2. 执行该函数
 obj.fn()
// 3. 删除该函数
 delete obj.fn

 

3. 实现

3.1基于ES3实现call

Function.prototype.es3Call = function (context) {
    var context = context || window;
    context.fn = this;
    var args = [];
    // arguments是类数组对象,遍历之前需要保存长度,过滤出第一个传参
    for (var i = 1, len = arguments.length ; i < len; i++) {
      // 避免object之类传入
      args.push('arguments[' + i + ']');
    }
    var result = eval('context.fn('+args+')');
    delete context.fn;
    return result;
  }
console.error(add.es3Call(obj, 3, 4)); // 10

 

3.2基于ES6实现call,es6的rest参数

Function.prototype.es6Call = function (context) {
    var context = context || window;
    context.fn = this;
    var args = [];
    for (var i = 1, len = arguments.length; i < len; i++) {
        args.push(arguments[i]);
    }
    var result = context.fn(...args);
    delete context.fn;
    return result;
}

 

4.例子

测试一下自己是否真的理解了call

function fn1(){
   console.log(1);
}
function fn2(){
    console.log(2);
}

fn1.call(fn2);     //输出 1
 
fn1.call.call(fn2);  //输出 2

 

分析

/**
* fn1.call(fn2)
* fn2.fn = fn1
* fn2.fn()
* delete fn2.fn
*
* fn1.call.call(fn2)
* fn2.fn=fn1.call
* fn2.fn()->fn2.call()->递归->最后执行window.fn2()
* delete fn2.fn
*/

 

 

参考博客:

https://www.cnblogs.com/donghezi/p/9742778.html (例子分析太复杂了,让人难以理解)

https://blog.csdn.net/u010377383/article/details/80646415 (原理讲的很好)

 

posted on 2019-08-23 16:49  SmilingEye  阅读(202)  评论(0编辑  收藏  举报

导航