理解嚴格模式下JavaScript的this指向的變化

全局代碼中的this

  • 全局中的代碼無論是否處於嚴格模式下,它的this都執行Windowjavascript

    console.log(this) // Window
    複製代碼

箭頭函數的this

  • 箭頭函數的this由上下文的詞法做用域決定,即在哪定義的就指向哪裏的this
() => {
      console.log(this) // window 或 global,在全局定義指向全局
  }
  obj = {
      fn: () => {
          console.log(this) // obj 在obj對象中定義,可是指向全局(箭頭函數時,obj沒法確認環境)
      }
  }
複製代碼

普通函數中的this

  • 直接調用函數(在全局或者其餘函數內)html

    • 在非嚴格模式下,this默認指向全局變量(window或global)java

      ```js
      // 在瀏覽器中,全局對象是window, 在NODE中是global
      function test() {
        console.log(this) // Window 或者 global
        (function(){
           console.log(this) // Window 或者 global
        })
      }
      test() 
      ```
      複製代碼
      • 在嚴格模式下,this將保持進入執行環境的值,因此,若是沒有指定環境,則默認undefined
      function test() {
        console.log(this) // undefined 
        (function(){
           console.log(this) // undefined
        })
      }
      test() 
      複製代碼
      • 特殊點:當函數做爲回調函數時,須要注意是否隱式綁定了所屬對象,例如:看成爲setTimeout的參數時,就默認將函數綁定了window對象
      // setTimeout是window的方法,可使用window.setTimeout調用
      // 調用函數時,對象訪問大體路線:window -> setTimeout -> 獲取參數中test的引用參數 -> 執行 test 函數
      function test() {
         console.log(this) 
      }
      setTimeout(test, 100); // window 或 global
      複製代碼
  • 做爲對象方法調用則指向當前對象es6

    • 注意:以下列代碼中的將對象的方法賦值給其餘變量在調用,this將按上面的普通方法直接調用函數規則處理
    var a = 'global'
    function name() {
         console.log('name', this.a) // 經過普通調用方法直接調用,在嚴格模式下this爲undefined,運行報錯,在非嚴格模式下global
    }
    var obj = {
     fn: function () {
         console.log('inner', this.a) // obj 經過對象obj調用,this指向該對象與模式沒有關係
         name() 
     },
     a: 'obj'
    }
    obj.fn()
    var newFn = obj.fn()
    newFn() // 嚴格模式爲undefined,非嚴格爲window或者global,按普通方法直接調用的規則處理
    function test(fn){
       fn()  
    }
    test(obj.fn) // 至關於將fn=obj.fn, 嚴格模式爲undefined,非嚴格爲window或者global
    newObj = {fn: 2}
    test(newObj.fn=obj.fn) // 至關於 fn = newObj.fn = obj.fn, 嚴格模式爲undefined,非嚴格爲window或者global
    複製代碼
  • 執行new操做時,構造函數的this指向正在構造的新對象瀏覽器

    function TEST(){
        this.a = 'obj';
        console.log(this) //new操做時 TEST { a: 'obj'} this指向正在構造的對象(返回的對象)
    }
    var o = new TEST();
    console.log(o); // TEST { a: 'obj'} this指向剛剛構造的對象
    複製代碼
    • 對es6的class Person {} 使用new操做時,this執行它調用的環境
    class MyTest {
      constructor (callback) {
        this.callback = callback
        callback() // 指向window
      }
      func () {
        this.callback() // 指向MyTest
      }
    }
    // let的值不會綁定到window上,沒法用window.name訪問
    let name = 'global'
    function Test () {
      console.log(this, this.name)
    }
    new Test() // window 使用let輸出 '', 使用var輸出global
    let c = new MyTest(Test) // window 使用let輸出 '', 使用var輸出global
    c.func() // MyTest{} undefined
    複製代碼
    • 其餘狀況下Constructor的執行與普通函數沒有區別,誰調用它則指向誰
    // 當函數直接調用的時候,在非嚴格模式下,this指向window;嚴格模式爲undefined
    // 當函數做爲對象的屬性調用的時候,this指向這個對象;
    // p1.constructor指向Person的構造函數(Person()函數自己),
    // 在p1.constructor()時,Person是做爲p1的屬性調用的,因此this指向p1;
    // 當調用p2 = p1.constructor;p2();時,其實就至關於直接調用Person();因此this指向window
    var name = 'global'
    function Person() {
        this.name = 'person';
        console.log(this);
    }
    var p1 = new Person();
    p1.constructor();        // Person {name: "person"}
    var p2 = p1.constructor;
    p2();   // window
    複製代碼
  • 設置call/apply/bind後調用,則指向其第一個參數的this,若是爲空則在嚴格模式下指向undefined,在非嚴格模式下指向window或globalbash

    // 語法
    // 一、函數.apply(對象, [參數列表]) 
    // 二、函數.call(對象, arg1,arg2,arg3…argn)
    // 三、函數.bind(對象)
    // 'use strict'
    var a = 'global'
     function name() {
         console.log('name', this.a)
     }
     function name2() {
         console.log('name2', this)
     }
     var obj = {
         a: 'obj'
     }
     name.call(obj) // obj this指向經過call綁定的obj對象
     // name2.call() // 嚴格模式爲undefined,非嚴格模式爲widow或global
    複製代碼
  • 做爲一個dom事件處理函數,它的this指向添加處理事件的元素(一些瀏覽器在使用非addEventListener的函數動態添加監聽函數時不遵照這個約定)閉包

    // html
    <div id="A">
      <div id="B"></div>
    </div>
    // javascript
    var a = document.getElementById('A');
    var b = document.getElementById('B');    
    function logs (e) {
        console.log(e.target, e.target===this); // 當e.target與e.currentTarget相等時爲true
        console.log(e.currentTarget, e.currentTarget===this); // 老是true
    }
    a.addEventListener('click', logs, false);
    // 點擊A時,
    // 輸出 A節點信息,true \n A節點信息, true
    // 點擊B時,
    // 輸出 B節點信息,false \n A節點信息, true
    // currentTarget表示實際綁定處理事件的元素
    // target表示觸發事件的元素(如點擊B)
    // 因此處理事件中的this指向實際添加處理事件的元素
    複製代碼
  • 做爲一個內聯事件處理函數,app

    • 當代碼被內聯on-event 處理函數調用時,它的this指向監聽器所在的DOM元素,與模式沒有關係
    <button onclick="alert(this.tagName.toLowerCase());">Show this</button>
    複製代碼
    • 當代碼包裹在內部函數中時,在非嚴格模式指向window或global對象(即非嚴格模式下調用的函數未設置this時指向的默認對象),在嚴格模式下爲undefined
    <button onclick="alert((function(){return this})());">Show inner this</button>
    複製代碼

閉包的this指向

閉包的執行至關因而返回一個函數,而後將這個返回的函數執行,所以和普通函數的直接調用相同dom

var box={
    user: 'zs',
    getThis:function(){
        return function(){
            return this;   
        };
    }
}
console.log(box.getThis()()); // 指向全局,非嚴格爲window,嚴格爲undefined
複製代碼
相關文章
相關標籤/搜索