this指向

this指向解析

幾個月之前就想要寫一些博客,記錄本身的學習歷程,但因爲各類緣由,沒能動工,2019的第一個月即將過去,今天終於下定決心抓住一月的尾巴,勤奮一把,激勵本身在2019能有所收穫。因此這第一篇,就從面試常見的考點this指向開始吧。面試

總的來講,咱們始終要牢記的一句話就是:this始終指向最終調用它的那個對象數組

1.直接做爲一個函數被調用,this指向window

function demo () {
    var a = '這是第一個demo的a'
    console.log(this)
    console.log(this.a)
}
demo()
// window
// undefined
複製代碼

爲何此處this.a是undefined呢?由於咱們能夠把demo當作window.demo,window對象並無a這個屬性,因此是undefined。若是但願打印出'這是第一個demo',能夠將代碼改成以下示例:bash

function demoUpdate () {
    this.a = '這是第一個demo的a'
    console.log(this)
    console.log(this.a)
}
demoUpdate()
// window
// 這是第一個demo的a
複製代碼

2.做爲對象的方法被調用,this指向這個對象

var obj = {
    a: '這是第二個demo的a',
    func: function () {
        console.log(this)
        console.log(this.a)
    }
}
obj.func()
// 指向obj
// 這是第二個demo
複製代碼

3.做爲構造函數被調用,this指向這個構造函數的實例對象

function Constructor () {
    var a = '這是第三個demo的a'
    this.a = '這是第三個demo的b'
    console.log(this)
    console.log(this.a)
}
var func = new Constructor()
// 指向Constructor的實例對象
// 這是第三個demo的b
複製代碼

爲何此處的this.a指向的倒是'這是第三個demo的b',而不是a呢?這就涉及到構造函數的繼承問題了,這裏用var a 聲明的a在Constructor的實例對象,也就是func中實際上並不存在,只有this.a聲明的這個a對象才被func對象繼承,存在於func中,因此當打印this.a時,打印的就是'這是第三個demo的b'app

4.若是一個函數中有this,且這個函數中包含多個對象,this指向它的上一級對象,即最後調用它的那個對象

var obj = {
    a: '這是第四個demo的外層a',
    child: {
        a: '這是第四個demo的內層a',
        func: function () {
            console.log(this)
            console.log(this.a)
        }
    }
}
obj.child.func()
// 指向obj.child
// 這是第四個demo的內層a
複製代碼

5.若是遇到return,若return的是一個對象,則this指向這個對象,若return的不是對象,則仍然指向這個函數的實例(null例外,雖然null是一個對象,但仍然指向對象的實例)

function Constructor () {
    this.a = '這是第五個demo的a'
    return {}
}
var b = new Constructor
console.log(b.a) //undefined
複製代碼

由於此時b指向的是Constructor生成的實例對象,而這個對象是個空對象,沒有a屬性函數

function Constructor () {
    this.a = '這是第六個demo的a'
    return function () {}
}
var b = new Constructor
console.log(b.a)  // undefined,此時b指向的是Constructor的新的實例對象,也就是function () {}
複製代碼

再看return的不是對象的狀況學習

function Constructor () {
    this.a = '這是第七個demo的a'
    return 1
}
var b = new Constuctor
console.log(b.a)  // 這是第七個demo的a
複製代碼

此時b指向的是新生成的Constructor的實例對象,這個實例對象的a屬性即爲:這是第七個demo的aui

function Constructor () {
    this.a = '這是第八個demo的a'
    return undefined
}
var b = new Constructor
console.log(b.a) // 這是第八個demo的a,理由同上
複製代碼
function Constructor () {
        this.a = '這是第九個demo的a'
        return null
    }
    var b = new Constructor
    console.log(b.a) // 這是第九個demo的a
複製代碼

改變this的指向

首先看一個沒有改變this指向時的例子this

var obj = {
    a: '這是第十個demo的a',
    func1: function () {
        console.log(this.a)
    },
    func2: function () {
        setTimeout( function () {
            this.func1()
        }, 1000)
    }
}
obj.func2() // this.func1 is not a function 
複製代碼

爲何此處報錯而沒有打印‘這是第十個demo的a’呢?由於當調用obj.func2時,func2中的setTimeout函數實質上是調用window對象的setTimeout函數,this指向window,而window對象沒有func1這個屬性,因此報錯spa

1.使用箭頭函數改變this的指向

箭頭函數中沒有this綁定,必須經過做用域鏈決定this的值,若是箭頭函數被非箭頭函數包含,則this指向最近的一層非箭頭函數的this,不然,this爲undefinedcode

var obj = {
    a: '這是第十一個demo的a',
    func1: function () {
        console.log(this.a)
    },
    func2: function () {
        setTimeout(() => {
            this.func1()
        }, 1000)
    }
}
obj.func2() // 這是第十一個demo的a
複製代碼

2.在函數內部使用that = this改變this的指向

var obj = {
    a: '這是第十二個demo的a',
    func1: function () {
        console.log(this.a)
    },
    func2: function () {
        var that = this
        setTimeout(function() {
            that.func1()
        }, 1000)
    }
}
obj.func2() // 這是第十二個demo的a
複製代碼

3.使用call,apply, bind改變this的指向

首先區分這三個函數的區別: call和apply改變this的指向後當即執行,而bind僅綁定this的指向,並不當即執行,返回改變this指向後的函數

call和bind的參數能夠有多個,第一個參數爲綁定的this的指向,後面的參數爲傳入函數的參數

apply只有兩個參數,第一個參數爲綁定的this的指向,第二個參數爲包含傳入函數的參數的數組

以上內容爲我本身記錄的知識點,若是後面有補充的,我會繼續添加,此博客僅作記錄知識點使用,如有幸被大佬們指點,不對的還煩請指正。

相關文章
相關標籤/搜索