关于 this

当 JavaScript 执行到一段可执行代码时,会创建一个可执行上下文。执行上下文可以理解为当前代码的执行环境。 执行上下文的周期可以分为两个阶段。

  1. 创建阶段

    在这个阶段,可执行上下文会创建变量对象、建立作用域链以及确定 this 指向问题

  2. 代码执行阶段

    创建完成后,就开始执行代码,完成变量赋值、函数引用以及执行其他代码。

如何判断 this 的指向

this 对象是基于当前运行环境执行时所绑定的。

  1. 隐式绑定

    通过某个对象的属性指向函数,再通过这个对象属性调用函数。这就是函数在调用的时候给绑定了上下文对象,或者说被这个对象拥有。

    function getName() {
      console.log('this:%s,name:%s', this, this.name);
    }
    var name = 'globalName';
    var bar = {
      name: 'barName',
      getName: getName,
    };
    bar.getName();
    

    getName是一个单独函数,严格来说它不属于 bar,只不过在调用的时候使用bar.getName引用函数,也就是说 getName 函数被调用的时候添加了对 bar 的引用,当函数有引用文对象的时候,函数内部的 this 就会被绑定到 bar。

    所以上述代码执行的结果如下图所示:
    js 关于 this指向问题 函数

    现在代码稍微修改一下

    var name = 'globalName';
    function getName() {
      console.log('this:%s,name:%s', this, this.name);
    }
    var bar = {
      name: 'barName',
      getName: getName,
    };
    //将引用地址赋值给一个新的变量
    const fn = bar.getName;
    fn();
    

    运行结果如下:
    js 关于 this指向问题 log

    函数getName丢失了绑定对象,变成了 全局对象(或者 undefined,这取决于是否函数是否在严格模式下执行)。

  2. 显示绑定

    通过 call 或者 apply 方法强制把 this 绑定到指定的对象。

    var name = 'globalName';
    function getName(...params) {
      console.log('this:%s,name:%s,params:%s', this, this.name, params);
    }
    var bar = {
      name: 'barName',
    };
    getName.apply(bar, [10, 11]);
    getName.call(bar, 10, 12);
    const fn = getName.bind(bar, 10, 13);
    fn();​

    温馨提示

    applycall区别仅是其他参数传递方式不同。applycall第一个参数如果传递的值为基本类型,JavaScript 会有一个装箱的操作,也就是把基本类型包装成它对应的对象形式。


    为了解决隐式绑定出现 this 丢失的问题,我们可以增加一个中间函数解决这个问题。

    var name = 'globalName';
    function getName() {
      console.log('this:%s,name:%s', this, this.name);
    }
    var bar = {
      name: 'barName',
    };
    function foo() {
      //强制将getName函数的this绑定到bar
      return getName.apply(bar);
    }
    foo();

    3.new 绑定

    使用 new 的方式创建的实例,this 指向这个实例(新创建的对象)。 使用 new 操作符创建的实例,经历 4 个步骤。

    1. 创建一个新对象
    2. 新对象的 proto 属性指向函数的原型
    3. 将构造函数的作用域赋给新对象(所以 this 是指向这个新对象)。执行构造函数中的代码,为这个新对象添加属性
    4. 如果函数没有返回其他对象,则返回这个新对象
      function Person(name, age) {
        this.name = name;
        this.age = age;
      }
      // 在这里可以把Person当作一个构造函数
      // 所以在new Person的时候就相当于把它的作用域指向了p
      // 所以Person中的this是指向p的
      const p = new Person();​

    4.默认绑定

    this 不能使用其他三个规则的则使用默认绑定。默认绑定就是函数独立运行所在的位置,通常都是指全局对象或者 undefined,这取决函数是否在严格模式下执行。

    关于箭头函数的 this

    箭头函数本身是没有 this 这个概念的,内部的 this 取决于包裹箭头函数的第一个普通函数 this。

    总结

    1. 是否是使用 new 的方式生成?如果是则 this 绑定到该对象
    2. 是否使用 call、apply 以及 bind 等显示绑定方式?
    3. 是否使用隐式绑定?则 this 绑定到引用上下文对象
    4. 都不是则使用默认规则

    箭头函数是根据当前此法作用域来决定 this,具体来说就是继承外层函数绑定的 this。

以上就是【js 关于 this指向问题】的全部内容了,欢迎留言评论进行交流!

赞(0) 踩(0)
发表我的评论

最新评论

  1. 暂无评论