this
是 JS 這門語言的魅力之一——靈活方便又難以捉摸,即便是有經驗的程序員,若是不仔細也有可能搞錯,關於this
的用法也成爲許多公司的經典面試題。程序員
若是你寫過 Java ,你可能接觸過this
——通常指向當前對象,實際上,這時候this
的含義已經肯定了,由於Java屬於編譯期綁定,而JS屬於運行期綁定
,因此致使this的含義在運行過程當中可能有多種變化。面試
進一步說,this和它聲明環境無關,而徹底取決於他的執行環境。務必牢記這句話。app
//讀如下代碼以前,必須先閱讀《哈利·波特》原著。(笑) var name = '羅恩'; var aaa = { name: '哈利', say: function () { console.log(this.name); } } var bbb = { name: '赫敏', say: aaa.say } var ccc = aaa.say; aaa.say(); //哈利 bbb.say(); //赫敏 ccc(); //羅恩
咱們看第一行,aaa.say()
調用的是aaa
對象自己的say()
方法,此時this
指代的是aaa對象自己,因此此時輸出固然就是aaa
對象的name
屬性值。異步
第二行,bbb.say();
輸出赫敏
必定和JS新手們的常識不相符,其實只要牢記「this取決於執行環境」就能想明白。bbb對象是怎麼聲明自身的say方法的呢?它只是把aaa對象的say方法引用過來,注意,引用的是一個方法而非一個對象,而aaa.say存儲的是一個匿名函數,因此這種寫法和如下代碼並無什麼區別。函數
var bbb = { name: '赫敏', say: function () { console.log(this.name); } }
第三行的ccc()是在最外層執行,也就是在全局對象window
下。因此ccc()
執行的時候this
指代的就是window
對象。而在window對象下聲明瞭name屬性,就至關於window.name = '羅恩'
,輸出的固然就是羅恩
。this
固然,也有特殊狀況,那就是 setTimeout 和 setInterval 。
我把開頭的aaa對象的聲明改爲:code
var aaa = { name: '哈利', getName: function () { setTimeout(function(){ console.log(this.name); },100) } }
僅僅是在console.log(this.name)
外面套了一個setTimeout
,猜猜原來三行的輸出會是什麼?對象
答案:3個羅恩
。
也就是說,三次this
,指代的都是window
對象。ip
關於爲何會這樣,我這裏暫時不詳細展開,由於涉及到JS異步回調的知識,若是你僅僅想快速熟悉this的用法,那麼只要記住這個特殊狀況便可。這個知識點曾經是阿里仍是小米的面試題。get
顯然,三個羅恩不是我想要的,畢竟韋斯萊夫人的孩子已經夠多了。那麼咱們只需稍微改寫一下這個方法:
getName: function () { //在setTimeout外存儲this指代的對象 var that = this; setTimeout(function(){ //this.name變成了that.name console.log(that.name); },100) }
輸出就又正常了。
顯然,that
並非一個關鍵字,只是一個你們解決這種狀況時約定俗成的名字。若是你願意,也能夠叫thatGuy。固然,考慮到可能會有其餘人維護你的代碼,仍是用that
比較好。
之因此寫這篇文章,是爲了我下一篇文章作鋪墊:
《快速理解JavaScript中apply()和call()的用法》敬請期待~~