關於 js 中 this 指向的問題

關於 js 中 js 指向的問題

本文章經過代碼的運行來描述 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

this 丟失的狀況:

此種狀況是針對 結論二 的不足所做出的補充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])

apply 這些函數特殊的地方:

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 綁定

這裏說的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 > 函數調用

總結:

  • 在正常,無任何調用的狀況下, this 是指向全局變量 window 的
  • this 他所在的函數被調用了,那麼他就會指向該函數, 而且會指向他最近的一個調用對象
  • 若是調用對象被賦值後調用,若是沒有綁定 this, 那麼他的指向將會丟失
  • 隱式/顯示調用能夠改變 this 指向,並且比隱式調用的優先級要大
  • 隱式/顯示調用都不能改變箭頭函數的指向, 箭頭函數與 new 的構造函數相矛盾
  • this 改變的優先級: 箭頭函數 = new > bind/apply/call > 函數調用

本文中的全部例子都在 GitHub 中: https://github.com/Grewer/JsDemo/blob/master/jsthis/index.html

相關文章
相關標籤/搜索