Javascript--ECMAScript 之 this

Posted cuner

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 对象脱离了关系,相当于不带任何修饰符的函数调用,所有运用了默认规则指向全局对象。

 

隐式丢失

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

<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(); //this 指向全局对象 输出global;

       </script>

其它:在一些流行的javascript库中事件处理器会把回调函数的this强制绑定到触发事件的DOM元素上。

  •  显示绑定

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 则是立即调用 

  • new调用 :指向创建的对象

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

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

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

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

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

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

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

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

技术图片

 

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

 

 技术图片

 

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

 

技术图片

 

以上是关于Javascript--ECMAScript 之 this的主要内容,如果未能解决你的问题,请参考以下文章

Javascript (ECMAScript5) 的细节和违反直觉的地方

Javascript (ECMAScript5) 的细节和违反直觉的地方

JavaScript ECMAScript5基础语法

ES6 javascript 中的 at 符号 (@) 有啥作用? (ECMAScript 2015)

React 1 - Javascript (ECMAscript) 重学习

javascript ECMAScript中