本文章經過代碼的運行來描述 this 的具體指向:javascript
console.log('普通狀況', this) // window
在普通狀態下, this 指向的是全局變量 windowhtml
function foo() { console.log('普通函數體', this) } foo() // window
在函數體內, this 也是指向全局變量 windowjava
在正常,無任何調用的狀況下, this 是指向全局變量 window 的react
function get() { console.log(this.a); } var obj = { a: 2, get } obj.get() // 2
在 obj.get 調用下, get 中 this 指向的就是 obj 這個對象git
var obj2 = { obj, a: 1 } obj2.obj.get() // 2
能夠看到,儘管有二層調用, this 指向的仍是最近一層中的 thises6
從而得出, this 他所在的函數被調用了,那麼他就會指向該函數, 而且會指向他最近的一個調用對象github
此種狀況是針對 結論二
的不足所做出的補充windows
function get() { console.log(this.a); } var obj = { a: 2, get } // 更換調用方式: var getIns = obj.get getIns() // undefined
若是調用對象被賦值, 在指向以後他實際上是並無調用對象的, 固然他也不會指向 window, 因此 this 指向的是 undeapp
var o1 = { text: 'o1', fn: function () { return this.text } } var o3 = { text: 'o3', fn: function () { console.log('o3', this) var fn = o1.fn return fn() } } console.log('o3 丟失 this 的狀況', o3.fn()) // undefined
能夠看到 即便在 o3 中的 fn 裏被調用, this 依舊是處於空的指向
此場景是爲了增強場景五所做出的驗證函數
若是調用對象被賦值後調用,若是沒有綁定 this, 那麼他的指向將會丟失
緣由的話,等你看完這篇文件,大抵能夠明白了: http://www.ruanyifeng.com/blog/2018/06/javascript-this.html
var getIns = obj.get.bind(obj) getIns() // 2
套用情景 5 this 丟失的場景, 能夠看到, 如今打印的是咱們想要的值了
var o3 = { text: 'o3', fn: function () { var fn = o1.fn return fn.call(this) } } console.log('情景 8 o3 丟失 this 的狀況修改', o3.fn()) // undefined
該場景使用 call/apply
這兩個函數的做用是同樣的,惟一不同在於傳參:
call(this,1,2,3)
apply(this, [1,2,3])
var array = ['a', 'b']; var elements = [0, 1, 2]; array.push.apply(array, elements); console.log(array); // ["a", "b", 0, 1, 2]
經過 apply 直接 push 了多個參數
在 es6 以後 也快使用這種方式: array.push(...elements)
class Foo { name = "mike" say() { console.log(this.a) } } var FooIns = new Foo() FooIns.say() // undefined
class 中的函數, 這也屬於一種 this 丟失的場景
熟悉 react 的人應該就知道這個場景
這裏說的new 綁定和情景 9 是不同, 說的是構造函數的綁定:
// es5代碼 function Foo2() { this.bar = "LiLz" } const Foo2Ins = new Foo2() console.log(Foo2Ins.bar) // LiLz
在上面情景一中 this 指向的是 window, 在場景 10 中, 經過 new 成功將 this 綁定在了 Foo2Ins 上
class Foo3 { constructor() { this.bar = 'lisa' } } var Foo3Ins = new Foo3() console.log(Foo3Ins.bar) // lisa
從這裏能夠看到 new 的做用, 雖然改變指向只是他的一部分功能
隱式/顯示調用能夠改變 this 指向,並且比隱式調用的優先級要大
function foo2() { 'use strict' console.log('嚴格模式下的 this', this) } foo2() // undefined
能夠看到在嚴格模式下 普通的 this 指向就是會丟失
咱們來看看箭頭函數對應的 this 有什麼區別
const bar = () => { 'use strict' console.log('箭頭函數', this) } bar() // windows
即便在嚴格模式下 箭頭函數中的 this 也不會是 undefined
const get2 = () => { console.log(this, this.a); } var obj3 = { a: 2, get2 } obj3.get2() // window, undefined
隱式調用沒法改變其指向
obj3.get2.bind(obj3)() // 同場景 14 obj3.get2.call(obj3) // 場景 14
這裏能夠得出結論, 隱式/顯示調用都不能改變箭頭函數的指向
const Foo4 = () => { this.bar = "LiLz" } const Foo4Ins = new Foo4() console.log(Foo4Ins.bar) // TypeError: Foo4 is not a constructor
遇到 new 時, 能夠看到箭頭函數,他是沒法被做爲構造函數的
class Foo5 { name = "mike" say = () => { console.log(this.name) } } var Foo5Ins = new Foo5() Foo5Ins.say() // mike
至此能夠得出 this 改變的權重: 箭頭函數 = new > bind/apply/call > 函數調用
本文中的全部例子都在 GitHub 中: https://github.com/Grewer/JsDemo/blob/master/jsthis/index.html