<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
關於 this,我們得先從執行上下文說起。我們知道:執行上下文中包含了變數環境、詞法環境、外部環境,當然也包括 this,具體你可以參考下圖:
從圖中可以看出,this 是和執行上下文繫結的,也就是說每個執行上下文中都有一個 this。執行上下文主要分為三種——全域性執行上下文、函數執行上下文和 eval 執行上下文,所以對應的 this 也只有這三種——全域性執行上下文中的 this、函數中的 this 和 eval 中的 this。
不過由於 eval 我們使用的不多,所以本文我們對此就不做介紹了,如果你感興趣的話,可以自行搜尋和學習相關知識。
那麼接下來我們就重點講解下全域性執行上下文中的 this和函數執行上下文中的 this。
首先我們來看看全域性執行上下文中的 this 是什麼。
你可以在控制檯中輸入console.log(this)
來列印出來全域性執行上下文中的 this,最終輸出的是 window 物件。所以你可以得出這樣一個結論:全域性執行上下文中的 this 是指向 window 物件的。這也是 this 和作用域鏈的唯一交點,作用域鏈的最底端包含了 window 物件,全域性執行上下文中的 this 也是指向 window 物件。
現在你已經知道全域性物件中的 this 是指向 window 物件了,那麼接下來,我們就來重點分析函數執行上下文中的 this。還是先看下面這段程式碼:
function foo() { console.log(this); } foo();
我們在 foo 函數內部列印出來 this 值,執行這段程式碼,列印出來的也是 window 物件,這說明在預設情況下呼叫一個函數,其執行上下文中的 this 也是指向 window 物件的。估計你會好奇,那能不能設定執行上下文中的 this 來指向其他物件呢?答案是肯定的。通常情況下,有下面三種方式來設定函數執行上下文中的 this 值。
你可以通過函數的call方法來設定函數執行上下文的 this 指向,比如下面這段程式碼,我們就並沒有直接呼叫 foo 函數,而是呼叫了 foo 的 call 方法,並將 bar 物件作為 call 方法的引數。
let bar = { myName: " name1 ", test1: 1, }; function foo() { this.myName = " name2 "; } foo.call(bar); console.log(bar); console.log(myName);
執行這段程式碼,然後觀察輸出結果,你就能發現 foo 函數內部的 this 已經指向了 bar 物件,因為通過列印 bar 物件,可以看出 bar 的 myName 屬性已經由“name1”變為“name2”了,同時在全域性執行上下文中列印 myName,JavaScript 引擎提示該變數未定義。
其實除了 call 方法,你還可以使用bind和apply方法來設定函數執行上下文中的 this,僅僅是語法稍有不同。
要改變函數執行上下文中的 this 指向,除了通過函數的 call 方法來實現外,還可以通過物件呼叫的方式,比如下面這段程式碼:
var myObj = { name: " name ", showThis: function () { console.log(this); }, }; myObj.showThis();
在這段程式碼中,我們定義了一個 myObj 物件,該物件是由一個 name 屬性和一個 showThis 方法組成的,然後再通過 myObj 物件來呼叫 showThis 方法。執行這段程式碼,你可以看到,最終輸出的 this 值是指向 myObj 的。
所以,你可以得出這樣的結論:使用物件來呼叫其內部的一個方法,該方法的 this 是指向物件本身的。
其實,你也可以認為 JavaScript 引擎在執行myObject.showThis()
時,將其轉化為了:
myObj.showThis.call(myObj)
接下來我們稍微改變下呼叫方式,把 showThis 賦給一個全域性物件,然後再呼叫該物件,程式碼如下所示:
var myObj = { name: " time ", showThis: function () { this.name = " bang "; console.log(this); }, }; var foo = myObj.showThis; foo();
執行這段程式碼,你會發現 this 又指向了全域性 window 物件。
所以通過以上兩個例子的對比,你可以得出下面這樣兩個結論:
你可以像這樣設定建構函式中的 this,如下面的範例程式碼:
function CreateObj() { this.name = " time "; } var myObj = new CreateObj();
在這段程式碼中,我們使用 new 建立了物件 myObj,那你知道此時的建構函式 CreateObj 中的 this 到底指向了誰嗎?
其實,當執行 new CreateObj() 的時候,JavaScript 引擎做了如下四件事:
這樣,我們就通過 new 關鍵字構建好了一個新物件,並且建構函式中的 this 其實就是新物件本身。
就我個人而言,this 並不是一個很好的設計,因為它的很多使用方法都衝擊人的直覺,在使用過程中存在著非常多的坑。下面咱們就來一起看看那些 this 設計缺陷。
我認為這是一個嚴重的設計錯誤,並影響了很多開發者。
至於如何解決?你可以在函數中宣告一個變數 self 用來儲存 this。當然也可以使用 ES6 中的箭頭函數來解決這個問題。
上面我們已經介紹過了,在預設情況下呼叫一個函數,其執行上下文中的 this 是預設指向全域性物件 window 的。
不過這個設計也是一種缺陷,因為在實際工作中,我們並不希望函數執行上下文中的 this 預設指向全域性物件,因為這樣會打破資料的邊界,造成一些誤操作。如果要讓函數執行上下文中的 this 指向某個物件,最好的方式是通過 call 方法來顯示呼叫。
這個問題可以通過設定 JavaScript 的“嚴格模式”來解決。在嚴格模式下,預設執行一個函數,其函數的執行上下文中的 this 值是 undefined,這就解決上面的問題了。
回顧下內容:
首先,在使用 this 時,為了避坑,你要謹記以下三點:
最後,我們還提了一下箭頭函數,因為箭頭函數沒有自己的執行上下文,所以箭頭函數的 this 就是它外層函數的 this。
以上就是深入理解函數執行上下文 this的詳細內容,更多關於函數執行上下文 this的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45