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