• this


    this应该算是前期比较容易混淆的一个关键字了,在这里,我就打算按照我的理解来说一下

    首先呢,this的值是跟运行时被调用的位置相关的,而不是词法作用域。

    也就是说,他的绑定的值很可能是动态的,不同的调用位置,很可能值就不一样,比如说:

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

    默认绑定

    独立的函数调用,它的作用域是作用在全局的,这种绑定规则最常见并且是优先级最低的一种绑定规则。来一个例子

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

    在浏览器中执行,会发现,如果foo()作为一个函数单独调用,那么this指向的就是全局对象windows。

    但是呢,也有一种例外,如果函数使用的严格模式的话,那么全局对象将无法使用默认绑定,this将会绑定到undefined,还是刚才的例子:

    function foo() {
      "use strict"
      console.log(this.a);
      console.log(this === window);
    }
    var a = 2;
    foo();  //Uncaught TypeError: Cannot read property 'a' of undefined

    可以看到,foo直接抛出一个error,说this是undefined,取不到a,如果用到严格模式的时候,可以稍微注意下这个区别

    隐式绑定

    这一条规则考虑的是是否有上下文对象,举个例子

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

    在这种情况下,foo会使用obj的上下文对象来引用函数,此时的this指向的就是obj。

    那么如果是嵌套对象这种的,会怎么处理呢?

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

    可以看到,实际上此时foo中的this指向了离他最近的对象obj,也就是说,对象属性引用链的最后一层会影响它的调用位置

    还有一种情况:

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

    显式绑定

    很简单,显式绑定就是手动直接改变其this指向的一种方式,这个主要是用几种api来实现的

    function foo() {
      console.log(this.a);
    }
    var obj = {
      a: 2,
    };
    foo.call(obj);
    foo.apply(obj);
    var f = foo.bind(obj);
    f();

    上面就是显式绑定的常见的三种形式

    new绑定

    这个主要是new 函数()的绑定形式的,这个的this指向的是函数构造出的那个对象,new的时候,它的执行过程可以大概执行以下几步

    创建一个全新的对象

    这个新对象会被执行prototype连接

    新对象绑定到函数调用的this

    如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

    注意最后一句话,如果函数没有返回对象,那么就会返回函数调用的新对象,如果返回了一个对象呢,那么结果就是直接返回这个对象

    var abc = {
      a: 10
    }
    function foo() {
      return abc;
    }
    foo.prototype = {
      b: 20
    };
    var a = new foo();
    console.log(a === abc);   // true
    console.log(a.b);         // undefined
    function bar() {
      this.a = 10;
    }
    bar.prototype = {
      b: 20
    };
    var b = new bar();
    console.log(b.a);   //  10
    console.log(b.b);   // 20

    以上四种常见的this绑定方式已经介绍的差不多了,那么问题来了,谁的优先级更高呢

    很明显,默认绑定的优先级最低,就不展开说了

    显式绑定与隐式绑定哪个优先级高呢,举个例子

    function foo() {
      console.log( this. a );
    }
    var obj1 = {
      a: 2,
      foo: foo
    };
    var obj2 = {
      a: 3,
      foo: foo
    };
    obj1.foo(); // 2
    obj2.foo(); // 3
    obj1.foo.call( obj2 ); // 3
    obj2.foo.call( obj1 ); // 2

    很明显,显式绑定优先级要高于隐式绑定

    那么new绑定和显式绑定谁更高呢,来再看个例子

    function foo(something) {
      this.a = something;
    }
    var obj1 = {};
    var bar = foo.bind( obj1 );
    bar( 2 );
    console.log( obj1.a ); // 2
    var baz = new bar(3);
    console.log( obj1.a ); // 2
    console.log( baz.a ); // 3

    很明显,new的优先级会更高

    所以,这样的话,优先级排序就出来了,分别为

    new绑定  > 显式绑定 > 隐式绑定 > 默认绑定

    以上就是大家常用到的几种,不过es6出现了一种箭头函数,箭头函数理论上不能应用上面四种的任意一种,它的this是根据代码的词法作用域来走的,比如说

    function foo() {
      return (a) => {
        console.log( this.a );
      };
    }
    var obj1 = {
      a: 2
    };
    var obj2 = {
      a: 3
    };
    var bar = foo.call( obj1 );
    bar.call( obj2 ); // 2
  • 相关阅读:
    JavaScript 移动端拖动元素
    JavaScript轮播图
    JavaScript缓动动画函数封装
    JavaScript mouseenter和mouseover的区别
    类欧几里得算法
    AGC043 A~C 解题报告
    「UOJ495」新年的促销
    「BZOJ4842」Delight for a Cat
    Atcoder AGC002 解题报告
    Atcoder AGC001 解题报告
  • 原文地址:https://www.cnblogs.com/luzhanshi/p/10996517.html
Copyright © 2020-2023  润新知