JavaScript中的this指向問(wèn)題詳解
前言
相信我,只要記住本文的 7️⃣ 步口訣,就能徹底掌握 JS 中的 this 指向。
先念口訣:箭頭函數(shù)、new、bind、apply 和 call、歐比屆點(diǎn)(obj.)、直接調(diào)用、不在函數(shù)里。
按照口訣的順序,只要滿足前面某個(gè)場(chǎng)景,就可以確定 this 指向了。
接下來(lái)按照口訣順序?qū)λ鼈冞M(jìn)行詳解,文中示例代碼都運(yùn)行在 Chrome 的 Console 控制臺(tái)中。
文末有精心準(zhǔn)備的練習(xí)題,用于檢驗(yàn)學(xué)習(xí)成果,別忘了試試~
1. 箭頭函數(shù)
箭頭函數(shù)排在第一個(gè)是因?yàn)樗?this 不會(huì)被改變,所以只要當(dāng)前函數(shù)是箭頭函數(shù),那么就不用再看其他規(guī)則了。
箭頭函數(shù)的 this 是在創(chuàng)建它時(shí)外層 this 的指向。這里的重點(diǎn)有兩個(gè):
- 創(chuàng)建箭頭函數(shù)時(shí),就已經(jīng)確定了它的 this 指向。
- 箭頭函數(shù)內(nèi)的 this 指向外層的 this。
所以要知道箭頭函數(shù)的 this 就得先知道外層 this 的指向,需要繼續(xù)在外層應(yīng)用七步口訣。
2. new
當(dāng)使用 new 關(guān)鍵字調(diào)用函數(shù)時(shí),函數(shù)中的 this 一定是 JS 創(chuàng)建的新對(duì)象。
讀者可能會(huì)有疑問(wèn),“如果使用 new 關(guān)鍵調(diào)用箭頭函數(shù),是不是箭頭函數(shù)的 this 就會(huì)被修改呢?”。
我們?cè)诳刂婆_(tái)試一下。
func = () => {}
new func() // throw error
從控制臺(tái)中可以看出,箭頭函數(shù)不能當(dāng)做構(gòu)造函數(shù),所以不能與 new 一起執(zhí)行。
3. bind
bind 是指 Function.prototype.bind() 。
多次 bind 時(shí)只認(rèn)第一次 bind 的值
易錯(cuò)點(diǎn)
function func() {
console.log(this)
}
func.bind(1).bind(2)() // 1
箭頭函數(shù)中 this 不會(huì)被修改
bind 與 new
易錯(cuò)點(diǎn)
function func() {
console.log(this, this.__proto__ === func.prototype)
}
boundFunc = func.bind(1)
new boundFunc() // Object true,口訣 2 優(yōu)先
4. apply 和 call
apply() 和 call() 的第一個(gè)參數(shù)都是 this,區(qū)別在于通過(guò) apply 調(diào)用時(shí)實(shí)參是放到數(shù)組中的,而通過(guò) call 調(diào)用時(shí)實(shí)參是逗號(hào)分隔的。
箭頭函數(shù)中 this 不會(huì)被修改
易錯(cuò)點(diǎn)
func = () => {
// 這里 this 指向取決于外層 this,參考口訣 7 「不在函數(shù)里」
console.log(this)
}
func.apply(1) // Window,口訣 1 優(yōu)先
bind 函數(shù)中 this 不會(huì)被修改
易錯(cuò)點(diǎn)
function func() {
console.log(this)
}
boundFunc = func.bind(1)
boundFunc.apply(2) // 1,口訣 3 優(yōu)先
5. 歐比屆點(diǎn)(obj.)
function func() {
console.log(this.x)
}
obj = { x: 1 }
obj.func = func
obj.func() // 1
這里就不用代碼例證箭頭函數(shù)和 bind 函數(shù)的優(yōu)先級(jí)更高了,有興趣可自行嘗試吧。
6. 直接調(diào)用
在函數(shù)不滿足前面的場(chǎng)景,被直接調(diào)用時(shí),this 將指向全局對(duì)象。在瀏覽器環(huán)境中全局對(duì)象是 Window,在 Node.js 環(huán)境中是 Global。
先來(lái)個(gè)簡(jiǎn)單的例子。
function func() {
console.log(this)
}
func() // Window
來(lái)一個(gè)復(fù)雜的例子,外層的 outerFunc 就起個(gè)迷惑目的。
function outerFunc() {
console.log(this) // { x: 1 }
function func() {
console.log(this) // Window
}
func()
}
outerFunc.bind({ x: 1 })()
7. 不在函數(shù)里
不在函數(shù)中的場(chǎng)景,可分為瀏覽器的 <script /> 標(biāo)簽里,或 Node.js 的模塊文件里。
- 在 <script /> 標(biāo)簽里,this 指向 Window。
- 在 Node.js 的模塊文件里,this 指向 Module 的默認(rèn)導(dǎo)出對(duì)象,也就是 module.exports。
非嚴(yán)格模式
嚴(yán)格模式是在 ES5 提出的。在 ES5 規(guī)范之前,也就是非嚴(yán)格模式下,this 不能是 undefined 或 null。所以**在非嚴(yán)格模式下,通過(guò)上面七步口訣,如果得出 this 指向是 undefined 或 null,那么 this 會(huì)指向全局對(duì)象。**在瀏覽器環(huán)境中全局對(duì)象是 Window,在 Node.js 環(huán)境中是 Global。
例如下面的代碼,在非嚴(yán)格模式下,this 都指向全局對(duì)象。
function a() {
console.log("function a:", this)
;(() => {
console.log("arrow function: ", this)
})()
}
a()
a.bind(null)()
a.bind(undefined)()
a.bind().bind(2)()
a.apply()
非嚴(yán)格模式下執(zhí)行結(jié)果為:

在嚴(yán)格模式下,執(zhí)行同樣的代碼進(jìn)行對(duì)比。記住要一次性將所有代碼復(fù)制粘貼到控制臺(tái)中,才能運(yùn)行在嚴(yán)格模式下(因?yàn)榈谝恍?"use strict" 才會(huì)對(duì)后面的代碼生效)。
"use strict"
function a() {
console.log("function a:", this)
;(() => {
console.log("arrow function: ", this)
})()
}
a()
a.bind(null)()
a.bind(undefined)()
a.bind().bind(2)()
a.apply()
嚴(yán)格模式下執(zhí)行結(jié)果為:

七步口訣在嚴(yán)格模式下和非嚴(yán)格模式下都是完備的,只是在非嚴(yán)格模式下 null 或 undefined 會(huì)被轉(zhuǎn)換為全局對(duì)象。所以我沒(méi)有將這點(diǎn)列入口訣中。
做題復(fù)習(xí)
先背誦口訣再做題,“箭頭函數(shù)、new、bind、apply 和 call、歐比屆點(diǎn)(obj.)、直接調(diào)用、不在函數(shù)里”。
1. 下面代碼執(zhí)行后,func.count 值為多少?
function func(num) {
this.count++
}
func.count = 0
func(1)
答案
func.count 值為 0。
按照口訣,func() 調(diào)用時(shí)屬于第 6 類「直接調(diào)用」。在非嚴(yán)格模式下,this 指向全局對(duì)象。this 跟 func 一點(diǎn)關(guān)系都沒(méi)有,所以 func.count 保持不變。so easy。
2. 以下箭頭函數(shù)中 this 指向誰(shuí)呢?
obj = {
func() {
const arrowFunc = () => {
console.log(this._name)
}
return arrowFunc
},
_name: "obj",
}
obj.func()()
func = obj.func
func()()
obj.func.bind({ _name: "newObj" })()()
obj.func.bind()()()
obj.func.bind({ _name: "bindObj" }).apply({ _name: "applyObj" })()
答案
// obj
// undefined
// newObj
// undefined
// bindObj
是不是很簡(jiǎn)單,你學(xué)廢了嗎?
總結(jié)
到此這篇關(guān)于JavaScript中的this指向問(wèn)題的文章就介紹到這了,更多相關(guān)js中this指向內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JS創(chuàng)建對(duì)象常用設(shè)計(jì)模式工廠構(gòu)造函數(shù)及原型
- JS對(duì)象創(chuàng)建與繼承的匯總梳理
- java鏈?zhǔn)絼?chuàng)建json對(duì)象的實(shí)現(xiàn)
- JS創(chuàng)建對(duì)象的四種方式
- JavaScript函數(shù)this指向問(wèn)題詳解
- 詳解JavaScript原型對(duì)象的this指向問(wèn)題
- JavaScript 中this指向問(wèn)題案例詳解
- JavaScript函數(shù)中this指向問(wèn)題詳解
- JavaScript創(chuàng)建對(duì)象的幾種方式及關(guān)于this指向問(wèn)題
相關(guān)文章
使用element-plus時(shí)重寫(xiě)樣式不起作用的問(wèn)題及解決方法
這篇文章給大家介紹使用element-plus時(shí)重寫(xiě)樣式不起作用的問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-09-09
JavaScript來(lái)實(shí)現(xiàn)打開(kāi)鏈接頁(yè)面的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇JavaScript來(lái)實(shí)現(xiàn)打開(kāi)鏈接頁(yè)面的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06
Electron實(shí)現(xiàn)多標(biāo)簽頁(yè)模式詳解
Electron 都發(fā)展這么多年了,讓人想不到的是,要實(shí)現(xiàn)一個(gè)多標(biāo)簽頁(yè)的功能居然沒(méi)有能用的輪子,本文就來(lái)用比較low的方案 - iframe手搓一個(gè)吧2024-11-11
js使用正則實(shí)現(xiàn)ReplaceAll全部替換的方法
JS?沒(méi)有提供replaceAll這樣的方法。使用正則表可以達(dá)成Replace?的效果,感興趣的朋友看看下面的示例2014-08-08
無(wú)constructor的class類還能new嗎問(wèn)題解析
這篇文章主要為大家介紹了無(wú)constructor的class類是否還能new的問(wèn)題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
用原生JS實(shí)現(xiàn)簡(jiǎn)單的多選框功能
這篇文章主要介紹了用原生JS實(shí)現(xiàn)簡(jiǎn)單的多選框功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-06-06
實(shí)例分析JS與Node.js中的事件循環(huán)
本篇文章通過(guò)實(shí)例給大家詳細(xì)分析了JS與Node.js中的事件的原理以及用法,大家學(xué)習(xí)一下吧。2017-12-12

