普通函數(shù)的this指向 簡單說說
首先,按照慣例,我們先舉個(gè)栗子:
var bar = 2; function foo() { this.bar = 1; this.getBar = function() { console.log(this.bar); } } var test = new foo(); var getBar = test.getBar; test.getBar(); //1 getBar(); //2
通過這個(gè)例子我們就能看到,雖然是同一個(gè)函數(shù),但是實(shí)際上得到的結(jié)果卻不一樣。這個(gè)原因相信大家都能知道。不知道的也告訴你:this其實(shí)是指向調(diào)用該函數(shù)的那個(gè)對(duì)象。那么當(dāng)我們?cè)谌汁h(huán)境中調(diào)用的時(shí)候,this自然就指向了全局環(huán)境。
那么到是有個(gè)問題:this為什么會(huì)隨調(diào)用者變化而變化?
這可能需要你繼續(xù)往下看看
深入說說那么如果說深層次的理解this的指向,我覺得大概可以從數(shù)據(jù)類型講起
我們都知道,棧中存放的是基本數(shù)據(jù)類型,也就是String、Number、Boolean、Symbol、Null、Undefined這七種數(shù)據(jù)類型,當(dāng)然Symbol是ES6新增的一個(gè)數(shù)據(jù)類型。那么堆中存放的就是一些引用類型了,如Obejct、Function。實(shí)際上當(dāng)我們定義一個(gè)引用類型的時(shí)候,js會(huì)同時(shí)定義一個(gè)地址指針指向內(nèi)存中的對(duì)象。
例如:當(dāng)我們聲明一個(gè)字面量對(duì)象時(shí)候let a = {num:1};實(shí)際上a中存放的是指向{num:1}的地址
現(xiàn)在我們解析一下上面那段代碼是如何執(zhí)行的
// 在全局環(huán)境下定義一個(gè)變量bar var bar = 2; function foo() { //在foo中也聲明了一個(gè)bar this.bar = 1; //在foo中聲明一個(gè)getBar函數(shù) this.getBar = function() { console.log(this.bar); } } //構(gòu)造函數(shù)模式自定義對(duì)象,將foo的this賦予test var test = new foo(); //將test中的getBar方法賦予getBar var getBar = test.getBar; //調(diào)用test中的getBar test.getBar(); //1 //調(diào)用getBar getBar(); //2
現(xiàn)在列出來一看,放佛恍然大悟,終于知道為啥輸出的是不同的結(jié)果了。那么我這里倒是有幾個(gè)問題
為什么調(diào)用同一個(gè)函數(shù)卻有不同的結(jié)果?
foo中的this是指向foo的,為什么foo中的函數(shù)可以取得外部的this?
為什么this會(huì)隨調(diào)用它的對(duì)象變化而變化?
ok,其實(shí)要弄清楚上述問題,我們需要明白一點(diǎn),函數(shù)也是個(gè)引用類型。那么我們上面講過,創(chuàng)建引用類型的時(shí)候會(huì)同時(shí)創(chuàng)建一個(gè)地址指針。那么我們就可以這樣理解上面的foo對(duì)象
實(shí)際上foo中的getBar只是存放了一個(gè)函數(shù)的地址而已*。那么這個(gè)函數(shù)并不是foo所私有。什么東西是foo的呢?一個(gè)值為1的bar和一個(gè)指向function() {console.log(this.bar);}函數(shù)的getBar而已。
這樣我們就不難理解,為什么調(diào)用同一個(gè)函數(shù)會(huì)有不一樣的結(jié)果了,因?yàn)檫@個(gè)函數(shù)并不是foo所私有。好比內(nèi)存就是深圳,函數(shù)就只是深圳的一套房。getBar就是這套房的鑰匙。那么一開始foo這個(gè)人建好了這房子,就他有這房子的鑰匙,那么當(dāng)然只有他能進(jìn)出該房子,后來有一天他把鑰匙多配了一把給了window這好朋友。于是乎window也能進(jìn)這套房了。給window配鑰匙的過程:var getBar = test.getBar;這里只是將該函數(shù)的地址賦給全局下的getBar而已,房子也只是一套房子,函數(shù)還是一個(gè)函數(shù)。
由于函數(shù)可以在不同的運(yùn)行環(huán)境執(zhí)行,所以需要有一種機(jī)制,能夠在函數(shù)體內(nèi)部獲得當(dāng)前的運(yùn)行環(huán)境(context)。所以,this就出現(xiàn)了,它的設(shè)計(jì)目的就是在函數(shù)體內(nèi)部,指代函數(shù)當(dāng)前的運(yùn)行環(huán)境。
所以當(dāng)window調(diào)用這個(gè)函數(shù)的時(shí)候,this就不是指向foo了。而是指向window。this是指向他們自己。window的衣服不會(huì)在進(jìn)了foo的房子以后就變成foo的衣服。
ok,我們現(xiàn)在再把剛剛的代碼重新注釋一下
// 在全局環(huán)境下定義一個(gè)變量bar var bar = 2; function foo() { //在foo中也聲明了一個(gè)bar this.bar = 1; //在foo中聲明一個(gè)getBar函數(shù),getBar存放該函數(shù)的地址 this.getBar = function() { console.log(this.bar); } } //構(gòu)造函數(shù)模式自定義對(duì)象,將foo的this賦予test var test = new foo(); //將test中的getBar方法的地址賦予全局的getBar var getBar = test.getBar; //調(diào)用test中的getBar函數(shù) test.getBar(); //1 //調(diào)用getBar函數(shù) getBar(); //2
于是乎我們就把普通的this指向弄明白了。順便還明白了堆棧的區(qū)別。接下來看看不普通的函數(shù)this指向是如何的
箭頭函數(shù)this指向箭頭函數(shù)內(nèi)沒有this,箭頭函數(shù)的this是父級(jí)函數(shù)的this
// 在全局環(huán)境下定義一個(gè)變量bar var bar = 2; function foo() { //在foo中也聲明了一個(gè)bar this.bar = 1; //在foo中定義一個(gè)箭頭函數(shù),getBar存放該函數(shù)的地址 this.getBar = () => { console.log(this.bar); } } //構(gòu)造函數(shù)模式自定義對(duì)象,將foo的this賦予test var test = new foo(); //將test中的getBar方法的地址賦予全局的getBar var getBar = test.getBar; //調(diào)用test中的getBar函數(shù) test.getBar(); //1 //調(diào)用getBar函數(shù) getBar(); //1
如果定義了箭頭函數(shù)的情況下,this執(zhí)行就不會(huì)隨意的改變了。普通函數(shù)的this是會(huì)跟隨調(diào)用者變化,但是箭頭函數(shù)就很特別,他只會(huì)繼承父級(jí)的this,而且一旦建立就不會(huì)改變了。所以在這里我們就可以看見,盡管全局下面調(diào)用getBar,但是實(shí)際上還是取到了foo的this。
因此箭頭函數(shù)不可以用來當(dāng)作構(gòu)造函數(shù)。因?yàn)樗旧硎菦]有this的!
所以箭頭函數(shù)使用的話需要與普通函數(shù)區(qū)別開這點(diǎn),它的this指向定義函數(shù)時(shí)候的父級(jí)。
后話關(guān)于this就介紹到這里,如果有什么不懂的歡迎隨時(shí)提問,我會(huì)隨時(shí)回答大家的問題。
那么最后,成功不在一朝一夕,我們都需要努力
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/96390.html
摘要:深入認(rèn)知前言關(guān)于,平時(shí)我們僅僅做到了使用,但是真的理解為什么這么使用嗎這里詳細(xì)介紹一些我們常用的語法。在以下,是沒有塊級(jí)作用域的,只有函數(shù)作用域。而如果在作用域中嵌套作用域,那么就會(huì)有作用域鏈。 本文當(dāng)時(shí)寫在本地,發(fā)現(xiàn)換電腦很不是方便,在這里記錄下。 深入認(rèn)知 Javascript 前言 關(guān)于 Javascript,平時(shí)我們僅僅做到了使用,但是真的理解為什么這么使用嗎? 這里詳細(xì)...
摘要:箭頭函數(shù)的尋值行為與普通變量相同,在作用域中逐級(jí)尋找。題目這次通過構(gòu)造函數(shù)來創(chuàng)建一個(gè)對(duì)象,并執(zhí)行相同的個(gè)方法。 我們知道this綁定規(guī)則一共有5種情況: 1、默認(rèn)綁定(嚴(yán)格/非嚴(yán)格模式) 2、隱式綁定 3、顯式綁定 4、new綁定 5、箭頭函數(shù)綁定 其實(shí)大部分情況下可以用一句話來概括,this總是指向調(diào)用該函數(shù)的對(duì)象。 但是對(duì)于箭頭函數(shù)并不是這樣,是根據(jù)外層(函數(shù)或者全局)作用域(...
摘要:執(zhí)行上下文和執(zhí)行棧是中關(guān)鍵概念之一,是難點(diǎn)之一。理解執(zhí)行上下文和執(zhí)行棧同樣有助于理解其他的概念如提升機(jī)制作用域和閉包等。函數(shù)執(zhí)行完成,函數(shù)的執(zhí)行上下文出棧,并且被銷毀。 前言 如果你是一名 JavaScript 開發(fā)者,或者想要成為一名 JavaScript 開發(fā)者,那么你必須知道 JavaScript 程序內(nèi)部的執(zhí)行機(jī)制。執(zhí)行上下文和執(zhí)行棧是JavaScript中關(guān)鍵概念之一,是Ja...
摘要:執(zhí)行上下文和執(zhí)行棧是中關(guān)鍵概念之一,是難點(diǎn)之一。理解執(zhí)行上下文和執(zhí)行棧同樣有助于理解其他的概念如提升機(jī)制作用域和閉包等。函數(shù)執(zhí)行完成,函數(shù)的執(zhí)行上下文出棧,并且被銷毀。 前言 如果你是一名 JavaScript 開發(fā)者,或者想要成為一名 JavaScript 開發(fā)者,那么你必須知道 JavaScript 程序內(nèi)部的執(zhí)行機(jī)制。執(zhí)行上下文和執(zhí)行棧是JavaScript中關(guān)鍵概念之一,是Ja...
摘要:本期推薦文章類內(nèi)存泄漏及如何避免,由于微信不能訪問外鏈,點(diǎn)擊閱讀原文就可以啦。四種常見的內(nèi)存泄漏劃重點(diǎn)這是個(gè)考點(diǎn)意外的全局變量未定義的變量會(huì)在全局對(duì)象創(chuàng)建一個(gè)新變量,如下。因?yàn)槔习姹镜氖菬o法檢測(cè)節(jié)點(diǎn)與代碼之間的循環(huán)引用,會(huì)導(dǎo)致內(nèi)存泄漏。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第一期,本周的主題...
閱讀 3897·2021-11-22 13:52
閱讀 3748·2019-12-27 12:20
閱讀 2475·2019-08-30 15:55
閱讀 2239·2019-08-30 15:44
閱讀 2328·2019-08-30 13:16
閱讀 651·2019-08-28 18:19
閱讀 1983·2019-08-26 11:58
閱讀 3530·2019-08-26 11:47