• 理解JavaScript Call()函数原理。


      最近在做面试题的过程中偶然碰到关于call函数的问题。然后再百度上查了查。偶然看到一篇文章:JavaScript中的call、apply、bind深入理解 抛开其对call函数基本概念的介绍还有其他原理的介绍。其中一段函数吸引了我。

    function fn1(){
       console.log(1);
    }
    function fn2(){
        console.log(2);
    }
    
    fn1.call(fn2);     //输出 1
     
    fn1.call.call(fn2);  //输出 2

       对于 fn1.call(fn2);我能够理解,这段代码仅仅 使得 fn1对象的this指向了fn2;但是最终不影响fn1函数的执行。因为fn1中不包含对this的操作。不过 fn1.call.call(fn2);实在是令我费解。我一时半会没有领会笔者的表达方式。花了很长时间去领会。最终还是看其他大神的博客才得以有所体会。究其原因还是在于对 call 函数的原理的研究。call 函数执行的时候到底干了什么????直接粘贴代码(摘自CSDN:深入JS系列(一:call, apply, bind实现)):

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

      在本机上调试后发现,执行  fn1.call.call(fn2); 的结果与 fn1.es3Call.es3Call(fn2);的结果一致。说明其基本还原了call函数的原理。故结合原理代码总结就是:

        1:把传入的第一个参数作为 call 函数内部的一个临时对象 context;

        2:给 context 对象一个属性 fn , 我称呼其为实际执行函数 context.fn ;让 this 关键字(仅仅是关键字,而不是this对象)指向这个属性 ,即 context.fn = this ; 注意 : 在这里的 this 对象指向的是调用call()函数的函数对象。如 fn1.call(fn2);在执行 call 函数时,call 函数内部的this指向的是fn1;然而 fn1.call.call(fn2);在执行 call() 函数时(注意这里必须是打了小括号“()”才算执行函数,fn1.call访问的是一个对象),call函数内部的 this 指向的是 fn1.call 。

        3:将传入call函数的其他参数,放入临时数组arr[];

        4:利用 eval (笔者采用es3的方法实现,也可以利用其他方式实现)。执行 context.fn( [args] ) ; 实际就是执行 this( [args] );结合第2点。

        5:执行完成后再把 context.fn 删除。返回执行 this( [args] ) 的结果。

       总结上边 5 点之后,能够大概解释出 fn1.call.call(fn2);的执行结果为什么是 输出 2 了。

       首先 调用call 函数时,也就是 fn1.call.call(fn2) ;加粗部分;先将 fn2 作为 临时的 context 对象 。然后 将 fn1.call这个函数对象作为 实际执行函数属性 : context.fn = fn1.call;注意:fn1.call会通过原型链找到最终的对象。其本质为 Function.prototype.call; 然后检查其他参数,没有了。直接执行 fn1.call()函数 ,即 context.fn();此时函数的本质还是 Function.prototype.call 函数对象。不过执行这个函数的环境还是在 Function.prototype.call()中,只不过是第一次调用的call()函数中。第一次调用的call()函数将this关键字指向了 fn2 ;故而 在  fn1.call.call(fn2) ;加粗部分的 函数中执行的 call函数执行过程中的 this指向的是 fn2;传入的参数为空,故而 新的 call()函数对象 的this关键字 被替换为window; 而执行 this()时,就是执行 fn2();不涉及 this操作。故最终输出2。

      这样就能够较好的解释 fn1.call.call(fn2);的输出结果了。为了验证这个过程。可以这段代码查看各个最终执行函数的this对象的指向:

    function func(){
        console.log(this);
    }
    func.call(func);     //输出func
    func.call.call(func); //输出window

      至于 func 为什么指向 window MDN官网上有具体解释(如下图)。如果执行 func.call.call(func,2);还会出来结果 Number{2}。
      

       以上。就是我目前对 js 中call 函数的理解。

  • 相关阅读:
    微信商城中使用微信支付接口获取用户地址
    微信支付开发流程
    沉默多年,重新开博
    Extjs 表单验证后,几种错误信息展示方式
    自己对Extjs的Xtemplate的忽略
    js execCommand
    支付宝支付
    C# 将短时间格式变长正常时间格式
    SortedDictionary
    sql操作
  • 原文地址:https://www.cnblogs.com/donghezi/p/9742778.html
Copyright © 2020-2023  润新知