• Javascript--ECMAScript 之 this


    ECMAScript中作用域一般是基于词法作用域是静态的,但是也有一种动态的作用域就是this:  this它不指向函数本事,也不指向函数的作用域

    this是在运行的时候绑定的并不是在定义的时候绑定的,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方法既是函数的调用位置。   

    如果要判断一个运行中函数的this的绑定,就需要找到这个函数的直接调用位置。找到后可以运用顺序运用下面的四条规则来判断this的绑定对象 

      1:有new调用?绑定到新创建的阿对象。 

      2:由call或者apply或者bind 调用?绑定到指定对象。

      3:由上下文对象调用?绑定到那个上下文对象。

      4:默认: 在严格模式下绑定到undefined,否则绑定到全局对象。

     箭头函数不会使用以上四条标准的绑定规则,而是根据当前的词法作用域来决定this,具体说,箭头函数会继承外层函数调用的this绑定

    调用位置

       通常来说,寻找调用位置就是寻找“函数被调用的位置”:最重要的是分析调用栈(就是为了到达当前执行位置所调用的所有函数),调用位置就在当前正在执行函数的前一个调用中。

    <script type="text/javascript">
            var a=0;
            function baz()
            {
                //当前的调用栈是 baz
                //因此当前调用位置是全局作用域
                var a=1;
                console.log("baz"+this.a);
                bar(); //bar 的调用位置
            }
            
            function bar()
            {
               //当前的调用栈是 baz--bar
               //因此当前调用位置在bar中
                var a=2;
                console.log("bar"+this.a);
                foo();  //foo的调用位置
            }
            
            function foo()
            {
                var a=3;
                console.log("foo"+this.a);
            }
            
            baz();  //  baz的调用位置
        </script>

       利用工具查找

         查找方法:可以在函数的第一行添加断点,运行代码的时候,调试器在那个位置停留的时候,会展示当前位置函数的调用列表,这就是调用栈。因此,当分析this绑定使用开发者工具调试得到调用栈,然后找到栈中的第二个元素,这就是真正的调用位置

     绑定规则

     找到了调用位置,就可以已经上面的四条规则来判断this的绑定对象。

    • 默认绑定  

     独立函数调用,可以把这条规则看作是无法应用其它规则时的默认规则 : 单独调用函数并且函数没有运行在严格模式下,this绑定到全局对象。

    看下面的代码

    <script type="text/javascript">
        function foo()
        {
          var a=5;
            console.log(this.a);
        }
        var a=2;
        foo();   //输出 2;
        </script>

     明显this指向了全局对象。 因为函数foo()是直接使用不带任何修饰的函数引用调用的

    如果调用的函数运行在严格模式下,this绑定到 undefinded

    <script type="text/javascript">
    
        function foo()
    
        {
    
               "use strict"
    
          var a=5;
    
               console.log(this.a);
    
        }
    
        var a=2;
    
        foo();   //访问不到
    
           </script>

    结果如下

     

    但是在严格模式下调用是可以正常访问的

           <script type="text/javascript">

        function foo()

        {

          var a=5;

          console.log(this.a);

        }

        "use strict"  //严格模式下调用

        var a=2;

        foo();   // 输出2

           </script>

    • 隐式绑定

    函数作为对象的属性,并通过这个属性调用函数

    函数作为对象的属性被调用时,this指向该对象,对象属性引用链中只有一层或者说最后一层在调用位置中起作用。 

    但是当对象的函数属性被赋值个别的变量,再调用时,this对象就指向全局对象。

    <script type="text/javascript">
        function foo()
        {
          var a=5;
          console.log(this.a);
        }
       var obj=
    {
             foo:foo,
             a:2
         }
       obj.foo(); //输出2  this指向obj
       
       var obj2=
    {
           a:7,
           obj:obj;
       }
       obj2.obj.foo();  //输出2  this 指向obj 而不是obj2
        </script>

     隐式丢失

     当对象的函数属性被当作参数传递后调用,效果等同于默认绑定

    <script type="text/javascript">
    
               function foo()
               {
                 var a=5;
                console.log(this.a);
               }
              var obj={
                foo:foo,
                a:2
               }
    
              var a="global";
    
              var bar=obj.foo; // bar其实引用的就是 foo()函数 和obj 对象脱离了关系
    
              bar(); //this 指向全局对象 输出global;
    
           </script>
     bar其实引用的就是 foo()函数 和obj 对象脱离了关系,相当于不带任何修饰符的函数调用,所有运用了默认规则指向全局对象。
    •  显示绑定

    cally(),apply(),bind 都是改变函数内部this的指向

    var obj = {
        x: 81,
    };
     
    var foo = {
        getX: function() {
            return this.x;
        }
    }
     
    console.log(foo.getX.bind(obj)());  //81
    console.log(foo.getX.call(obj));    //81
    console.log(foo.getX.apply(obj));   //81

    三个输出的都是81,但是注意看使用 bind() 方法的,他后面多了对括号。

    也就是说,区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。

    再总结一下:

    apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
    apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
    apply 、 call 、bind 三者都可以利用后续参数传参;
    bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 

    当把null,undefind作为this绑定的对象传入 call,apply,bind的时候,会被忽略,实际应用是默认绑定规则

        <script type="text/javascript">
                function foo()
                {
                    var a=3;
                    console.log(this.a);
                }
                var a=100;
                
                foo.call(null);  //输出100
            </script>
    • new调用 :指向创建的对象

    说明:javaScript 中没有构造函数,只有构造调用

    使用new来调用函数,或者发生构造函数调用时,会自动指向下面的操作

    1:创建一个全新的对象。

    2:这个对象会被执行【prototype】连接

    3:这个新对象会绑定到函数调用的this

    4: 如果函数没有返回其它对象,那么new表达式中的函数会自动返回这个新对象。

     即是:如果函数有返回对象,就返回对象,如果函数返回不是对象,或者没有定义返回值,就将新对象返回。

    使用new调用函数实际执行的步骤

    当返回值是对象的时候就返回函数返回值

     

     可以看到使用new 创建的对象 this :指向创建的对象, 不适用this创建的对象 this指向全局对象。

  • 相关阅读:
    20170926-构建之法:现代软件工程-阅读笔记
    我的swift的ui标签
    内存管理:内存泄漏和空悬指针
    闭包
    泛型,修饰符和异常处理
    类型转换,接口和扩展
    初始化2
    类的继承和初始化1
    枚举与可选值
    swift中的类和结构
  • 原文地址:https://www.cnblogs.com/cuner/p/12528571.html
Copyright © 2020-2023  润新知