JS的this指向理解

參考: http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

this在非箭頭函數下始終指向當前調用的對象。

1、爲什麼函數內部要設置this?

var obj = {
  foo: function () { console.log(this.bar) },
  bar: 1
};

var foo = obj.foo;
var bar = 2;

obj.foo() // 1
foo() // 2

this指的是函數運行時所在的環境,那麼函數的運行環境到底是怎麼決定的?爲什麼obj.foo()就是在obj環境執行,而一旦var foo = obj.foo,foo()就變成在全局環境執行?主要和數據在內存中存儲有關。

var obj = { foo:  5 };

上面的代碼將一個對象賦值給變量obj。JS引擎會先在堆內存裏生成一個對象{ foo: 5 },然後把這個對象的內存地址賦值給變量obj。如果要讀取obj.foo,引擎先從obj拿到內存地址,然後再從該地址讀出原始的對象,返回它的foo屬性。

var obj = { foo: function () {} };

這時,引擎會將函數單獨保存在內存中,然後再將函數的地址賦值給foo屬性的value屬性。

此時,由於函數是一個單獨的值,所以它可以在不同的環境(上下文)執行。

var f = function () {
  console.log(x);
};

JS允許在函數體內部,引用當前環境的其他變量。現在問題就來了,由於函數可以在不同的運行環境執行,所以需要有一種機制,能夠在函數體內部獲得當前的運行環境(context)。所以,this就出現了,它的設計目的就是在函數體內部,指代函數當前的運行環境。

var f = function () {
  console.log(this.x);
}

上面代碼中,函數體裏面的this.x就是指當前運行環境的x。

var foo = function () {
  console.log(this.x);
}
var x = 1;
var obj = {
  foo: foo,
  x: 2,
};

foo() // 1
obj.foo() // 2

在這裏插入圖片描述
回到本文開頭提出的問題,obj.foo()是通過obj找到foo,所以就是在obj環境執行。一旦var foo = obj.foo,變量foo就直接指向函數本身,所以foo()就變成在全局環境執行。

2、JS函數不同調用方式時this指向問題

函數調用方式主要分爲以下:

  • 作爲對象方法調用(指向當前的調用對象,具體看上面部分)
  • 作爲函數調用(非嚴格模型this指向window,嚴格模型指向undefined)
  • 作爲構造函數調用(this指向其實例)
  • 使用call或者applay調用(this指向第一個參數)

當函數作爲構造函數時,new一個構造函數的實例有以下幾個步驟:

  • 創建一個空對象obj
  • 設置原型鏈:obj.proto = 構造函數名.prototype
  • 讓構造函數內部的this指向obj(默認returnt爲當前this,構造函數renturn一個對象時,this指向return的對象)調用構造函數中的屬性,執行函數中的代碼,爲obj添加屬性。
  • 返回對象obj的地址

setTimeout有兩個參數,第一個是對象,第二個是間隔時間。由於setTimeout是window下的方法,那麼在函數內this指向window。

3、箭頭函數下的this

箭頭函數中this對象就是定義時所在的作用域,也就是說箭頭函數本身沒有this,內部的this就是外層代碼塊作用域中的this。

var a = 0
var obj = {
    a: 1,
    foo: ()=> {
        console.log(this.a)
    }
}
obj.foo()  //0

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章