美文网首页
this全面解析

this全面解析

作者: 唐井儿_ | 来源:发表于2019-12-06 13:49 被阅读0次
    1 定义

    谁调用的函数,该函数的this就指向谁。

    2 四种绑定规则

    2.1 默认绑定,this指向全局对象,严格模式下绑定到undefined

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

    2.2 隐式绑定,this绑定到调用函数的上下文对象上

    • 在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this间接绑定到这个对象上,比如obj.foo属性:
    function foo() {
      console.log(this.a);
    }
    var a = 1;
    var obj = {
      a: 2,
      foo: foo // 核心!
    };
    obj.foo(); // 2
    
    • 隐式丢失问题:被对象所间接引用的函数,再次赋值后调用,会丢失this在该对象上的绑定
    // 情况一
    function foo() {
      console.log(this.a);
    }
    var a = 'I`m in global scope!';
    var bar = {
      a: 'I`m in bar`s scope!',
      foo:foo
    };
    var copyFoo = bar.foo; // 核心!重新赋值到另一变量上。copyFoo是bar.foo的一个引用,实际上,引用的是foo本身
    copyFoo(); // 'I`m in global scope!'
    
    // 情况二
    function foo() {
      console.log(this.a);
    }
    function doFoo(fn) {
      fn();
    }
    var a = 'I`m in global scope!';
    var bar = {
      a: 'I`m in bar`s scope!',
      foo:foo
    };
    // 函数传递是一种隐式赋值,所以结果和上例一样
    doFoo(bar.foo); // 'I`m in global scope!'
    setTimeout(bar.foo, 100); // 'I`m in global scope!'
    

    2.3 显式绑定,使用apply/call方法,显式绑定到指定对象上

    function foo() {
      console.log(this.a);
    }
    var bar = {
      a: 'I`m in bar`s scope!'
    };
    foo.call(bar); // 'I`m in bar`s scope!'
    
    • 使用“硬绑定”(bind)方法解决2.2中“隐式丢失问题”
    function foo() {
      console.log(this.a);
    }
    function doFoo(fn, context) {
      return function () { // 核心!
        fn.apply(context, arguments);
      }
    }
    var a = 'I`m in global scope!';
    var bar = {
      a: 'I`m in bar`s scope!',
      foo:foo
    };
    
    doFoo(bar.foo, bar)(); // 'I`m in bar`s scope!'
    setTimeout(doFoo(bar.foo, bar), 100); // 'I`m in bar`s scope!'
    
    // 此模式很有用,于是es5提供了内置的方法Function.prototype.bind,用法如下:
    setTimeout(bar.foo.bind(bar), 100); // 'I`m in bar`s scope!'
    
    • apply/call与bind的区别:使用前者时,会直接执行函数;而使用bind只是返回一个函数声明,要执行函数的话,还需'()'调用一下
    • bind实现方式、功能:1) 实现方式是把前者包裹起来返回一个函数声明;2) 功能之一就是可以把除了第一个参数(第一个参数用于绑定this)之外的其他参数都传给下层函数(“柯里化”的一种)
      2.4 new绑定,this绑定新创建的对象
    function Foo(a) {
      this.a = a;
    }
    var fooInstantiation = new Foo('1');
    fooInstantiation .a; // '1'
    
    3 优先级

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

    4 被忽略的this

    有些调用需要使用默认绑定规则,如果想“更安全”地忽略this绑定,可以用Object.create(null)

    Math.max.apply(Object.create(null), [1, 3]);
    
    5 特殊的箭头函数

    箭头函数并不会使用上边的四条规则,而是根据词法作用域来决定this。也就是说箭头函数会继承外层函数调用的this绑定,就和es6之前的self = this机制一样

    function foo() {
      setTimeout(() => {
        console.log(this.a);
      }, 0);
    }
    var a = 1;
    var obj = {a: 2};
    foo.call(obj); // 2
    
    function foo2() {
      var self = this;
      setTimeout(function() {
        console.log(self.a);
      }, 0);
    }
    foo2.call(obj); // 2
    
    • 虽然self = this和箭头函数看起来都可以取代bind(...),但本质上,它们想替代的是this机制
    • 良好的策略是:1) 只使用词法作用域完全抛弃错误this风格代码;2) 完全采用this风格,在必要时使用bind(...),尽量避免使用self = this和箭头函数;两种方式不要混用

    参考《你不知道的JavaScript》上卷 / Simpson, K.

    相关文章

      网友评论

          本文标题:this全面解析

          本文链接:https://www.haomeiwen.com/subject/ucisgctx.html