Skip to content

Latest commit

 

History

History
140 lines (95 loc) · 6.24 KB

this绑定,this词法.md

File metadata and controls

140 lines (95 loc) · 6.24 KB

this绑定,this词法

.首先说一下什么是this,this就是js里面的一个关键词,还可以理解为他是一个指向。既然是指向,就意味着他有一个绑定的概念,this自定义在每一个函数的作用域内,函数在不同的位置执行this的指向不同,因此,this指向不是取决于函数在哪定义,而是取决于函数在哪执行

首先明白一个概念,this不是定义在函数里面他就指向函数

绑定规则

  1. 默认绑定为全局(非严格模式)

    function foo() {
    console.log( this.a );
    }
    var a = 2;
    foo(); // 2
    

    一个简单的全局作用下的函数,它里面的this就是指向window。声明在全局作用域中的变量(比如 var a = 2)就是全局对象的一个同名属性。它们本质上就是同一个东西,并不是通过复制得到的,就像一个硬币 的两面一样。

    但是如果在严格模式下,this就不会指向window

    function foo() {
    console.log( this.a );
    }
    var a = 2;
    (function(){
    "use strict";
    foo(); // 2
    })();
    

    严格模式下,如果this没有由执行上下文定义,那么他为undefined

    1. 隐式绑定(作为对象方法)

      1. function foo() {
        console.log( this.a );
        }
        var obj = {
        a: 2,
        foo: foo
        };
        obj.foo(); // 2
        

        此时的foo函数作为obj对象的一个属性,当 foo() 被调用时,它的落脚点确实指向 obj 对象,当访问foo()时,隐式绑定就会把this绑定到这个对象,this的指向便会是obj对象,因此返回2,此时的this.a与obj.a没有区别

        1. 隐式丢失

          一个最常见的 this 绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,从而把 this 绑定到全局对象或者 undefined 上,取决于是否是严格模式。

          function foo() {
          console.log( this.a );
          }
          var obj = {
          a: 2,
          foo: foo
          };
          var bar = obj.foo; // 函数别名!
          var a = "oops, global"; // a 是全局对象的属性
          bar(); // "oops, global"
          

          此时虽然bar是obj.foo的一个引用,但是bar保存的是foo这个函数,因此此时的bar是没有任何修饰的一个函数,默认绑定为window或undefined

          1. 显式绑定

            1. 分析隐式绑定时,我们必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把 this 间接(隐式)绑定到这个对象上那么如果我们不想在对象内部包含函数引用,而想在某个对象上强制调用函数,该怎么做呢?

            可以使用call()和apply()方法。

            他们接受的第一个参数是一个对象,然后会把this绑定到这个对象

            function foo() {
            console.log( this.a );
            }
            var obj = {
            a:2
            };
            foo.call( obj ); // 2
            

            通过call()方法,就显式地把this绑定到了obj上面。如果第一个参数传入了原始值,那么系统就会使用包装类型转化为原始值的对象

          此时,因为Number对象中没有a属性,所以会打印出undefined,浅显易懂

          apply()也是一样,他们的区别仅在于参数列表上面,研究this不必考虑这些

          1. 硬绑定

            在隐式绑定中,仍然无法解决this的丢失问题,因此,在ES6中,出现了一个bind()函数,他可以硬式绑定this对象,而且绑定后就不可改变,不换函数在哪里调用。

            1. new绑定

              function foo(a) {
              this.a = a;
              }
              var bar = new foo(2);
              console.log( bar.a ); // 2
              

              我们知道在创建一个构造函数的实例时,会在函数内部生成一个this对象,然后将函数里面this属性值一一赋予,最后返回这个this对象,因此,接受这个返回值的变量便与this发生了绑定,我们可以通过bar.a这种形式访问任意一种属性

              优先级

              判断this

              现在我们可以根据优先级来判断函数在某个调用位置应用的是哪条规则。可以按照下面顺序来进行判断:

              1. 函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。 var bar = new foo()

              2. 函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是指定的对象。var bar = foo.call(obj2)

              3. 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上下文对象。var bar = obj1.foo()

              4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined否则绑定到全局对象。

              this词法

              我们之前介绍的四条规则已经可以包含所有正常的函数。但是 ES6 中介绍了一种无法使用这些规则的特殊函数类型:箭头函数

              箭头函数并不是使用 function 关键字定义的,而是使用被称为“胖箭头”的操作符 => 定义的。箭头函数不使用 this 的四种标准规则,而是根据外层(函数或者全局)作用域来决定 this。也就是当函数定义时就决定了他的this,箭头函数就继承外层函数的this

              箭头函数中,this指向的固定化,并不是因为箭头函数内部有绑定this的

              机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外

              层代码块的this。正是因为它没有this,所以也就不能用作构造函数。