Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

this

1. this

  • 对于普通函数:指向函数的调用者,即.前面的对象

    • 如果没有找到,那么:

      • 在非严格模式下,this 指向 window
      • "use strict";严格模式下,this 指向 undefined
  • 这里严格模式,指的是函数体是否处于严格模式下,如果只是调用的位置局部用了严格模式,那还是指向 window

      ```js
      function func() {
        console.log(this.a);
      }
    
      var a = "123";
      (function () {
        "use strict";
        func(); // 123
      })();
      ```
    
    • 常见隐式绑定

      var a = 'outer';
      var obj = {
          a: 'inner’,
          foo() {
              console.log(this.a);
          }
      }
      obj.foo(); // ①inner
      
      var bar = obj.foo;
      bar(); // ②outer
      
      setTimeout(obj.foo, 100); // ③outer
      
      • 位置 ①,obj.foo(),是 obj 通过.运算符调用了 foo(),所以指向的值 obj。
      • 位置 ②,是把 obj.foo 赋值给了 bar,实际上是把 foo 函数赋值给了 bar, bar() 调用的时候,没有调用者,所以使用的是默认绑定规则。
      • 位置 ③,是把 obj.foo 赋值给了 setTimeout,实际上调用的还是 foo 函数,调用的时候,没有调用者,所以使用的是默认绑定规则。
    • 一个很特别的隐式丢失例子

      function func() {
        console.log(this.a);
      }
      var a = 1;
      var obj1 = { a: 2, func: func };
      var obj2 = { a: 3 };
      obj1.func(); // 2
      (obj2.func = obj1.func)(); // 1
      
    • 对于 setInterval 和 setTimeout,如果他们的参数函数是用普通函数 function() {} 来定义,那么 this 也会指向 window

      • 对于老代码,会写很多 bind 来显式修复这个 this 指向,就是函数后面.bind(this)
      • 但箭头函数出现后,就不用这么麻烦了
  • 对于箭头函数:从所在作用域继承 this,自己并没有 this

    • 只有函数{ }能构成作用域

    • 对象的{ }和 if 语句的{ }都不构成作用域

    • 一个很特别的作用域继承例子

      function func() {
        return (a) => {
          console.log(this.a);
        };
      }
      var obj1 = {
        a: 2,
      };
      var obj2 = {
        a: 3,
      };
      
      var bar = func.call(obj1);
      bar.call(obj2); // 2,不是 3
      
      //箭头函数会捕获调用func时的 this,this一旦被确定,就不可更改
      

2. call apply bind

  • 相同点:

    • 三者都是 Function 原型上的方法:Function.prototype.xxxx()
    • 三者都用 this 作为第一个参数,显式绑定,如果不在意绑啥,可传 null
  • 不同点:

    • 函数调用 call 和 apply 时,返回的是调用执行后的返回值
    • 而调用 bind 时,是返回一个被绑定后的新函数,要再加()才能调用执行
    • 从参数 2 位置开始,call 接受的是一系列的参数,而 apply 接受的仅是一个数组更方便(其实用 ES6 的...展开运算符,也能直接展开后用 call)
  • 比如 Math.max 只是数字的方法,其实对数组也能用

    const arr = [1, 2, 3, 5];
    Math.max.call(null, ...arr);
    Math.max.apply(null, arr);