javascript系列之this總結

參考連接:
https://github.com/jawil/blog...javascript

在 JavaScript 中,this 是指當前函數中正在執行的上下文環境:java

  • 函數調用
  • 方法調用
  • 構造函數調用
  • 間接調用
  • 綁定函數調用
  • 箭頭函數
  • 易錯場景

函數調用

函數調用 表明了該函數接收以成對的引號包含,用逗號分隔的不一樣參數組成的表達式。git

函數調用中的this

function sum(a, b) {  
      console.log(this === window); // => true
      this.myNumber = 20; // 在全局對象中添加 'myNumber' 屬性
      return a + b;
    }
    // sum() 爲函數調用
    // this 在 sum() 中是全局對象 (window)
    sum(15, 16);     // => 31  
    window.myNumber; // => 20

當 sum(15, 16) 被調用時,JavaScript 自動將 this 設置爲全局對象,即 window。github

嚴格模式下,函數調用中的 this

嚴格模式由 ECMAScript 5.1 引進,用來限制 JavaScript 的一些異常處理,提供更好的安全性和更強壯的錯誤檢查機制。使用嚴格模式,只須要將 'use strict' 置於函數體的頂部。這樣就能夠將上下文環境中的 this 轉爲 undefined。這樣執行上下文環境再也不是全局對象,與非嚴格模式恰好相反。數組

function multiply(a, b) {  
      'use strict'; // 開啓嚴格模式
      console.log(this === undefined); // => true
      return a * b;
    }
    // 嚴格模式下的函數調用 multiply() 
    // this 在 multiply() 中爲 undefined
    multiply(2, 5); // => 10

嚴格模式不只在當前做用域起到做用,它還會影響內部做用域,即內部聲明的一切內部函數的做用域。安全

function execute() {  
      'use strict'; // 開啓嚴格模式
      function concat(str1, str2) {
        // 內部函數也是嚴格模式
        console.log(this === undefined); // => true
        return str1 + str2;
      }
      // 在嚴格模式下調用 concat()
      // this 在 concat() 下是 undefined
      concat('Hello', ' World!'); // => "Hello World!"
    }
    execute();

方法調用

當在一個對象裏調用方法時,this 表明的是對象它自身。
嚴格模式不只在當前做用域起到做用,它還會影響內部做用域,即內部聲明的一切內部函數的做用域。app

var calc = {  
      num: 0,
      increment: function() {
        console.log(this === calc); // => true
        this.num += 1;
        return this.num;
      }
    };
    // 方法調用,this 指向 calc
    calc.increment(); // => 1  
    calc.increment(); // => 2

構造函數調用

function Foo () {  
      console.log(this instanceof Foo); // => true
      this.property = 'Default Value';
    }
    // 構造函數調用
    var fooInstance = new Foo();  
    fooInstance.property; // => 'Default Value'

間接調用

間接調用表現爲當一個函數使用了 .call() 或者 .apply() 方法。.call() 和 .apply() 被用來配置當前調用的上下文環境。函數

var rabbit = { name: 'White Rabbit' };  
    function concatName(string) {  
      console.log(this === rabbit); // => true
      return string + this.name;
    }
    // 間接調用
    concatName.call(rabbit, 'Hello ');  // => 'Hello White Rabbit'  
    concatName.apply(rabbit, ['Bye ']); // => 'Bye White Rabbit'
兩個方法最主要的區別爲 .call() 接收一組參數,而 .apply() 接收一串參數做爲類數組對象傳遞。

綁定函數調用

綁定函數調用是將函數綁定一個對象,它是一個原始函數使用了 .bind() 方法。this

方法 .bind(thisArg[, arg1[, arg2[, ...]]]) 接收第一個參數 thisArg 做爲綁定函數在執行時的上下文環境,以及一組參數 arg1, arg2, ... 做爲傳參傳入函數中。 它返回一個新的函數,綁定了 thisArg。
function multiply(number) {  
      'use strict';
      return this * number;
    }
    // 建立綁定函數,綁定上下文2
    var double = multiply.bind(2);  
    // 調用間接調用
    double(3);  // => 6  
    double(10); // => 20
var numbers = {  
      array: [3, 5, 10],
      getNumbers: function() {
        return this.array;    
      }
    };
    // 建立一個綁定函數
    var boundGetNumbers = numbers.getNumbers.bind(numbers);  
    boundGetNumbers(); // => [3, 5, 10]  
    // 從對象中抽取方法
    var simpleGetNumbers = numbers.getNumbers;  
    simpleGetNumbers(); // => undefined 或者嚴格模式下拋出錯誤
.bind() 建立了一個永恆的上下文鏈並不可修改。一個綁定函數即便使用 .call() 或者 .apply()傳入其餘不一樣的上下文環境,也不會更改它以前鏈接的上下文環境,從新綁定也不會起任何做用。
function getThis() {  
      'use strict';
      return this;
    }
    var one = getThis.bind(1);  
    // 綁定函數調用
    one(); // => 1  
    // 使用 .apply() 和 .call() 綁定函數
    one.call(2);  // => 1  
    one.apply(2); // => 1  
    // 從新綁定
    one.bind(2)(); // => 1  
    // 利用構造器方式調用綁定函數
    new one(); // => Object
補充bind用法
bind()的另外一個最簡單的用法是使一個函數擁有預設的初始參數。這些參數(若是有的話)做爲bind()的第二個參數跟在this(或其餘對象)後面,以後它們會被插入到目標函數的參數列表的開始位置,傳遞給綁定函數的參數會跟在它們的後面。
function list() {
      return Array.prototype.slice.call(arguments);
    }
    
    var list1 = list(1, 2, 3); // [1, 2, 3]
    
    // Create a function with a preset leading argument
    var leadingThirtysevenList = list.bind(undefined, 37);
    
    var list2 = leadingThirtysevenList(); // [37]
    var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

箭頭函數

箭頭函數的設計意圖是以精簡的方式建立函數,並綁定定義時的上下文環境。prototype

箭頭函數並不建立它自身執行的上下文,使得 this 取決於它在定義時的外部函數。
class Point {  
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
      log() {
        console.log(this === myPoint); // => true
        setTimeout(()=> {
          console.log(this === myPoint);      // => true
          console.log(this.x + ':' + this.y); // => '95:165'
        }, 1000);
      }
    }
    var myPoint = new Point(95, 165);  
    myPoint.log();
箭頭函數一次綁定上下文後便不可更改,即便使用了上下文更改的方法.
var numbers = [1, 2];  
    (function() {  
      var get = () => {
        console.log(this === numbers); // => true
        return this;
      };
      console.log(this === numbers); // => true
      get(); // => [1, 2]
      // 箭頭函數使用 .apply() 和 .call()
      get.call([0]);  // => [1, 2]
      get.apply([0]); // => [1, 2]
      // Bind
      get.bind([0])(); // => [1, 2]
    }).call(numbers);

易錯場景

this 在內部函數中

var numbers = {  
      numberA: 5,
      numberB: 10,
      sum: function() {
        console.log(this === numbers);        // => true
        function calculate() {
          console.log(this === numbers);      // => false
          return this.numberA + this.numberB;
        }
        return calculate();
      }
    };
    numbers.sum();

解決辦法:return calculate.call(this);

this在回調函數中

function Animal(type, legs) {  
      this.type = type;
      this.legs = legs;  
      this.logInfo = function() {
        console.log(this === myCat);       // => false
        console.log('The ' + this.type + ' has ' + this.legs + ' legs');
      }
    }
    var myCat = new Animal('Cat', 4);  
    setTimeout(myCat.logInfo, 1000);

解決辦法:setTimeout(myCat.logInfo.bind(myCat), 1000);

把包含this的方法賦給一個變量

var name = "aa";
    var user = {
       name: 'hhh',
       sayName: function(){
           console.log(this.name);
       }
   }
   var test = user.sayName;
   test();   // aa

解決辦法:var test = user.sayName.bind(user);

參考連接

JavaScript This 之謎

相關文章
相關標籤/搜索