關於javascript中this的指向

關於javascript中this的指向

我GitHub上的菜鳥倉庫地址: 點擊跳轉查看其餘相關文章
文章在個人博客上的地址: 點擊跳轉

        學習javascript,必不可少的確定要理解this的指向。要學習this指向以前,就要先理解了我前面寫的幾篇文章,會更容易理解this的指向。javascript

        前面的文章說到, 執行上下文的建立階段,主要有三個內容:java

        一、建立變量對象;二、初始化做用域鏈;三、肯定this的指向。git

        前兩個內容我都做了詳細的解析了,在這裏,是時候要說一下第三個內容了,肯定this的指向。其實this的指向從一些理論知識上理解,是很複雜的,看過很多文章都沒有說的很清楚,反而說得人懵逼了。其實,this的指向是很是簡單的,明確了它的規律,不要被太多代碼表達形式的改變而影響了正常的認識思惟,那就能夠了。github

        好了,來個廣泛例子:函數

//全局環境
var a = 10;
function inner(){
    var a = 20;
    console.log(this.a);
}
inner();

        固然了,打印結果是10,this就是指向全局對象。學習

        好了,該解析this了,咱們都知道this的指向是函數被調用的時候肯定的。this

        簡單直接說結論:經過對象訪問屬性的方式執行函數,this就是指向這個對象,其餘狀況,嚴格模式下都是指向undefined,非嚴格模式下都是指向全局對象。code

        先解析上面例子,上面的inner函數是在全局環境中直接調用的:inner(   ),你們能夠理解這個調用,就是這一對方括號(),因此它是指向全局對象,因此this.a就是10。對象

//全局環境
var a = 10;
var example = {
    a : 20,
    b : this.a + 10
}
console.log(example.b);

        打印結果是多少?30嗎?錯了,不是經過example這個對象訪問b屬性,因此b裏面的this就是指向example嗎?錯了。ip

        我說的是對象訪問屬性的方式執行函數,你這個b屬性內容不是函數。因爲example是在全局環境中聲明的,因此裏面的this就是指向全局對象,或者說,this的肯定是函數被執行時候肯定的,你的函數呢?往上找,就是全局對象這個大函數了,因此這個this就是指向全局對象。

        固然了,若是你將example放進去某個函數裏面,對照一下個人結論,就會知道這個this在嚴格模式下就會指向undefined,非嚴格模式就是指向全局對象。例子以下:

//非嚴格模式下的全局環境
var a = 10;
function outer(){
    var example = {
        a : 20,
        b : this.a + 10
    }
    return example.b;
}
outer();//打印結果爲20
//嚴格模式下的全局環境
'use strict'
var a = 10;
function outer(){
    var example = {
        a : 20,
        b : this.a + 10
    }
    return example.b;
}
outer();//執行會報錯,由於this指向undefined

        還問爲何?由於outer函數被執行時候這個this才肯定啊,而outer這個函數是單獨調用啊,直接outer(  )這樣調用啊,因此就是結論中那樣啊。

        好了,那怎樣是屬於對象訪問屬性的方式執行函數呢?再來例子:

//全局環境
var a = 10;
var example = {
    a : 20,
    b : function(){
        return this.a;
    }
}
console.log(example.b());

        好了,此次打印結果是20了,由於經過了example訪問b屬性方式執行函數的,經過這個一點運算符的屬性訪問方式,叫作成員訪問。稍微改改再來例子:

//全局環境
var a = 10;
var example = {
    a : 20,
    b : function(){
        return this.a;
    }
}
var c = example.b;
console.log(c());

        仍是20嗎?不是了,非嚴格模式是10,嚴格模式報錯(後面都是非嚴格模式的例子),由於調用函數c,前面只是經過example.b將函數的地址傳給了c而已,你調用函數時候,仍是單獨調用啊。開始懂了對不對,再來例子:

//全局環境
var a = 10;
function runAway(){
    return this.a;
}
var example = {
    a : 20,
    b : runAway
}
console.log(example.b());

        若是你不假思索就能說是20的話,證實你已邁出了一大步了,同一個道理,是經過對象訪問屬性的方式執行函數的,我管你的b屬性是直接指向函數,仍是經過函數聲明指向函數的,反正你的this就是指向對象example。

        好了,結合上面的再改一改例子:

//全局環境
var a = 10;
function runAway(){
    return this.a;
}

function worker(fn){
    fn();
}
var example = {
    a : 20,
    b : runAway
}
worker(example.b);

        可能你會說,經過example.b這樣的的方式,我無論你有沒有跳出來的runAway,this確定是指向example啦,那就要重溫一下個人結論了,我說的是經過對象訪問屬性的方式執行函數,你執行了嗎,你有一對方括號嗎?可能你會說,他們傳入去worker函數,裏面就會加一對方括號執行啊,那就錯了。

        經過這種方式的執行函數,其實已經變味了,這種狀況和上面的例子:var c = example.b,而後c( )執行函數式同樣的,你只不過經過example.b將這個函數地址傳入了worker函數,而後執行而已。

        因此上面這個例子,就是結論中的其餘狀況咯,嚴格模式this指向undefined(固然這個例子會報錯,由於undefined沒有a屬性),非嚴格模式指向全局對象(固然這個例子會打印undefined,由於全局對象沒有b屬性)。

        好了,最後再舉一下其餘例子:

//全局環境
var a = 10;
var example = {
    a : 20,
    b : function(){
        return this.a;
    }
}
//例子一
console.log(example.b()); //打印結果爲20
//例子二
console.log((example.b)()); //打印結果爲20
//例子三
console.log((false || example.b)()); //打印結果爲10

        好了,在例子一中,很清楚明白就是常規的this指向了example。

        例子二中,你加了一個括號也沒用啊,我沒有將它的函數地址賦值其餘什麼變量啊,因此和例子一也是同樣的。

        至於例子三,咱們能夠這樣理解,你在括號裏面進行了一些其餘運算,因此經過example.b這個方式只是拿了函數地址出來運算,因此在例子三中,括號的結果是example.b這個結果,因此是拿到了一個函數的地址,最後調用的時候仍是單獨調用啊,就相似前面例子的worker函數那樣啊。

        網上還有不少像例子三那樣的古靈精怪的例子,其實很簡單,你運算過了,最後出來的東西再加方括號調用,就是單獨調用了。

        最後,好像忘了個很經常使用的構造函數的this指向:

//先來個構造函數Mankind
function Mankind(name){
    this.name = name;
}
//實例化對象Dad
var Dad = new Mankind('BaBa');
console.log(Dad.name); //打印結果爲BaBa

        很明白了,經過構造函數實例化對象,構造函數裏面的this就是指向這個實例化對象了。

相關文章
相關標籤/搜索