你不知道的this指向

1、this究竟是什麼

  • 學習this的第一步是明白this既不指向函數自身也不指向函數的詞法做用域,this其實是在函數被調用時發生的綁定,它指向什麼徹底取決於函數在哪裏被調用。

2、this的四種綁定規則

  • 默認綁定

    默認綁定通常發生在回調函數,函數直接調用;bash

    function fn() {
        console.log( this.a )
    }
    let a = 2;
    fn(); //2
    複製代碼

    this.a被解析成了全局變量a,函數調用時應用了this的默認綁定,所以this指向全局對象。在代碼中,fn是直接使用不帶任何修飾的函數引用進行調用的,所以只能使用默認綁定,沒法應用其餘規則。app

    若是使用嚴格模式(use strict),則不能將全局對象用於默認綁定,所以this會綁定到undefined函數

  • 隱式綁定

    通俗來講誰最終調用函數,this指向誰學習

    const obj = {
        name : 'lyq',
        getName () {
            console.log( this ); //obj
            console.log( this.name ); //lyq
        }
    };
    obj.getName();
    複製代碼

    鏈式調用只有最後一層在調用位置中起做用ui

    var obj2 = {
        name:'lyq',
        foo() {
            console.log( this.name )
        }
    }
    var obj1 = {
        name:'zs',
        obj2:obj2
    }
    
    obj1.obj2.foo(); // lyq
    複製代碼
    隱式丟失:

    一個最多見的this綁定問題是被隱式綁定的函數會丟失綁定對象,也就是你說它會應用默認綁定,從而把this綁定到全局對象或者undefined上,取決因而否是嚴格模式this

    var a = 100;
    
    var obj = {
        a : 2,
        foo() {
            console.log( this.a )
        }
    } 
    
    var bar = obj.foo;
    
    bar(); //100
    複製代碼

    obj.foo 是引用屬性,賦值給bar的實際上就是foo函數(即:bar指向foo自己,所以應用了默認綁定,指向全局屬性aspa

  • 顯示綁定call,apply,bind

    相對隱式綁定,this值在調用過程當中會動態變化,但是咱們就想綁定指定的對象,這時就用到了顯示綁定。prototype

    顯示綁定主要是經過改變對象的prototype關聯對象。具體使用上,能夠經過這兩個方法call(…)或apply(…)來實現(大多數函數及本身建立的函數默認都提供這兩個方法)。code

    function foo() {
        console.log( this.a )
    }
    
    var obj = {
        a : 2
    }
    
    foo.call( obj ) // 2
    
    複製代碼

    call和bind是同樣的,區別在於參數的設置上。對象

    硬綁定
    function foo() { 
        console.log( this.a );
    }
    
    var a = 2;
    
    var obj1 = { 
        a: 3,
    };
    
    var obj2 = { 
        a: 4,
    };
    
    var bar = function() {
      foo.call( obj1 );
    }
    
    setTimeout( bar, 100 ); // 3
    
    bar.call( obj2 );  //3
    
    複製代碼

    這裏須要注意下,雖然bar被顯示綁定到obj2上,對於函數bar 中的this確實被綁定到了obj2,而foo由於經過foo.call( obj1 )已經顯示綁定了obj1,因此在foo函數內,this指向的是obj1,不會由於bar函數內指向obj2而改變自身。因此打印的是obj1.a(即3)。

  • new綁定

    function foo(a) { 
        this.a = a;
    }
    
    var a = 2;
    
    var bar1 = new foo(3);
    console.log(bar1.a); // 3
    
    複製代碼

    使用new來調用foo()時,會創造一個新對象並把它綁定到foo()調用中的this上。

    3、箭頭函數this指向

    首先須要明確,箭頭函數不適用以上this的四種標準規則,而是根據外層(函數或者全局)做用域來決定this

    箭頭函數this的定義:箭頭函數中的this是在定義函數的時候綁定,而不是在執行函數的時候綁定 。

    var name = 'lyq';
    var obj = {
      name : 'zs',
      getName:function() {
        console.log( this.name )
      }
    }
    obj.getName(); //zs
    
    複製代碼
    var name = 'lyq';
    var obj = {
      name : 'zs',
      getName:()=>{
        console.log( this.name )
      }
    }
    obj.getName(); //lyq
    複製代碼

    所謂的定義時候綁定,就是this是繼承自父執行上下文中的this,好比這裏的箭頭函數中的this.name,箭頭函數自己所在的對象爲obj,而obj的父執行上下文就是window,所以這裏的this.name 實際上表示的是window.name,所以輸出的是lyq。(this只有在函數被調用,或者經過構造函數new Object()的形式纔會有this)

    注意簡單對象(非函數)是沒有執行上下文的!

    在setInterval和setTimeout中傳入函數時,函數中的this會指向window對象。箭頭函數可讓setTimeout裏面的this,綁定定義時所在的做用域,而不是指向運行時所在的做用域。

    export default {
      data () {
        return {
          name: zs,
        }
      },
      methods: {
        setName () {
          setTimeout(() => {
            this.name = 0;
          }, 500);
        }
      }
    }
    
    複製代碼

    此時函數的this指向的是定義它的時候的對象,也就是this指向了data內中對應的變量。若是使用function,this則會指向window,沒法得到當前對象。

相關文章
相關標籤/搜索