js中的this作用域全解析
this作用域問(wèn)題
一般來(lái)說(shuō),誰(shuí)調(diào)指誰(shuí)是一個(gè)基本原則,但是js和其他面向?qū)ο笳Z(yǔ)言稍微有些區(qū)別,雖然從某種程度上,這有助于幫我們判斷this指向問(wèn)題,但是并不能涵蓋所有的情況,建議從函數(shù)調(diào)用的5種方式展開(kāi)
- 1.函數(shù)式調(diào)用
- 2.方法調(diào)用模式
- 3.構(gòu)造函數(shù)調(diào)用模式(this指向?qū)嵗?/li>
- 4.call、apply、bind
- 5.特殊情況——箭頭函數(shù)
函數(shù)式調(diào)用
var age = 10
var person = {
age:12,
say(){
function f(){
console.log(this.age)
}
f()
}
}
person.say()// 10以此模式調(diào)用函數(shù)時(shí),this被綁定到全局對(duì)象。這是語(yǔ)言設(shè)計(jì)上的一個(gè)錯(cuò)誤。倘若語(yǔ)言設(shè)計(jì)正確,那么當(dāng)內(nèi)部函數(shù)被調(diào)用時(shí),this應(yīng)該仍然綁定到外部函數(shù)的this變量。這個(gè)設(shè)計(jì)錯(cuò)誤的后果就是方法不能利用內(nèi)部函數(shù)來(lái)幫助它工作,因?yàn)閮?nèi)部函數(shù)的this被綁定了錯(cuò)誤的值(全局對(duì)象),所以不能共享該方法對(duì)對(duì)象的訪問(wèn)權(quán)。
這種情況是不遵從所謂誰(shuí)調(diào)指誰(shuí)原則的
解決方法,內(nèi)部函數(shù)外使用一個(gè)變量保存this
var age = 10
var person = {
age:12,
say(){
var that = this
function f(){
console.log(that.age)
}
f()
}
}
person.say()// 12方法調(diào)用模式
當(dāng)一個(gè)函數(shù)被保存為對(duì)象的一個(gè)屬性時(shí),我們稱它為一個(gè)方法。當(dāng)一個(gè)對(duì)象的方法被調(diào)用時(shí),this被綁定到調(diào)用方法的對(duì)象。
var age = 10
var person = {
age:12,
say(){
console.log(this.age)
}
}
person.say()// 12這就有點(diǎn)像所謂的誰(shuí)調(diào)指誰(shuí)
在數(shù)組中的特例
var arr=[
function(){
console.log(this)
},
1,
2,
]
arr[0]()
//輸出結(jié)果
[f, 1, 2]很顯然,數(shù)組其實(shí)也是對(duì)象,雖然這種調(diào)用方式在寫(xiě)法上可能更加貼近函數(shù)調(diào)用模式,但是從打印結(jié)果來(lái)看,這很顯然屬于方法調(diào)用模式有點(diǎn)類似于arr.0()
反過(guò)來(lái)想,方法調(diào)用模式也可以寫(xiě)成
person['say']()
構(gòu)造器調(diào)用模式
如果在一個(gè)函數(shù)前面帶上 new 關(guān)鍵字來(lái)調(diào)用,那么背地里將會(huì)創(chuàng)建一個(gè)連接到該函數(shù)的prototype成員的新對(duì)象,同時(shí)this會(huì)被綁定到那個(gè)新對(duì)象上。
function foo(){
console.log('this is' + this)
}
new foo()
// this is [object]new 前綴也會(huì)改變r(jià)eturn 語(yǔ)句的行為,如果return 的值是對(duì)象,那么將會(huì)將這個(gè)對(duì)象返回,否則將返回默認(rèn)創(chuàng)建的新對(duì)象。
function foo(){
console.log('this is ' + this.a)
const obj = {
a:1
}
return obj
}
const f1 = new foo()
console.log(f1.a)
// this is undefied
// 1新知識(shí)點(diǎn),買一送一
這里可以看到,雖然返回的實(shí)例中確實(shí)有屬性a,但是在代碼執(zhí)行上仍然存在先后順序
call、apply、bind
沒(méi)什么好講的,更改作用域
特殊情況——箭頭函數(shù)
箭頭函數(shù)作為函數(shù)式調(diào)用設(shè)計(jì)失誤的解決方案而提出(例a如下)
var age = 10
var person = {
age:12,
say(){
var f=()=>{
console.log(this.age)
}
f()
}
}
person.say()// 12箭頭函數(shù)的特點(diǎn)中有一點(diǎn)是函數(shù)體內(nèi)的this對(duì)象,就是定義時(shí)所在的對(duì)象,而不是使用時(shí)所在的對(duì)象。
所以call、apply、bind對(duì)箭頭函數(shù)是不起作用的
var age = 10
var person = {
age:12,
say(){
var f=()=>{
console.log(this.age)
}
f.call({age:9})
}
}
person.say()// 12再看下面的例子
var age = 10
var person = {
age:12,
say:()=>{
console.log(this.age)
}
}
person.say()// 10這是因?yàn)閷?duì)象不構(gòu)成單獨(dú)的作用域,導(dǎo)致say箭頭函數(shù)定義時(shí)的作用域就是全局作用域。阮一峰的es6教程中也有相關(guān)內(nèi)容。
最后一個(gè)例子
var age = 10
var person = {
age:12,
say:()=>{
console.log(this.age)
}
}
var person1 = {
age:13,
say(){
var f=person.say
f()
}
}
person1.say()// 10這個(gè)例子看起來(lái)和例a很像,內(nèi)層函數(shù)f是一個(gè)箭頭函數(shù),雖然是person的一個(gè)屬性,那么結(jié)果是不是13呢,然而并不是,還是緊扣箭頭函數(shù)特征:函數(shù)體內(nèi)的this對(duì)象,就是定義時(shí)所在的對(duì)象,而不是使用時(shí)所在的對(duì)象。
該例中,person.say定義時(shí)在person內(nèi),對(duì)象不構(gòu)成單獨(dú)作用域,所以person.say定義時(shí)的作用域是全局作用域,所以f被調(diào)用時(shí)打印的結(jié)果為全局變量age=10
綜合例題
var length = 10;
function fn(){
console.log(this.length)
}
var obj = {
length: 5,
method: function(fn){
fn()
arguments[0]()
}
}
obj.method(fn, 1)
// 輸出結(jié)果
// 10
// 2
// 如果注釋掉第一行代碼 輸出結(jié)果
// 0
// 2(1)首先如果不注釋第一行代碼,obj調(diào)用自己的method方法,傳了兩個(gè)參數(shù),第一個(gè)是在全局定義的函數(shù)fn,第二個(gè)參數(shù)是number類型的常量
進(jìn)入method,立即調(diào)用fn,因?yàn)閒n是一個(gè)函數(shù)式調(diào)用,所以this指向全局,也就是window,打印結(jié)果是10
再看接下來(lái)執(zhí)行的arguments[0](),arguments是一個(gè)數(shù)組,表示函數(shù)的實(shí)參列表,也就是說(shuō)這個(gè)數(shù)組中包含兩個(gè)元素,第一個(gè)是傳進(jìn)去的fn,第二個(gè)是傳進(jìn)去的常量1,然后它調(diào)用了第0個(gè)元素表示的函數(shù),所以這里是方法調(diào)用模式中的特例,作為數(shù)組元素被調(diào)用,this指向數(shù)組本身,我們經(jīng)常會(huì)忽略數(shù)組中其實(shí)默認(rèn)是有l(wèi)ength屬性的,即使在寫(xiě)for循環(huán)的時(shí)候經(jīng)常會(huì)用,數(shù)組長(zhǎng)度為2,所以打印結(jié)果是2
(2)如果注釋了第一行代碼,不在全局定義length屬性,正常分析,length未定義,返回undefined,那么答案就錯(cuò)了,事實(shí)上,全局window是有l(wèi)ength屬性的,默認(rèn)值為0

這就是這道題隱藏最深的點(diǎn)了
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
JavaScript錯(cuò)誤處理之分析 Uncaught(in promise) error的
在開(kāi)發(fā)過(guò)程中,JavaScript的錯(cuò)誤處理是一個(gè)老生常談的話題,當(dāng)應(yīng)用程序發(fā)生未捕獲的異常時(shí),Uncaught(in promise) error是其中最常見(jiàn)的錯(cuò)誤類型,這篇文章將從多個(gè)方面詳細(xì)闡述這種錯(cuò)誤類型的原因與解決方案,感興趣的朋友一起看看吧2023-12-12
layer ui 導(dǎo)入文件之前傳入數(shù)據(jù)的實(shí)例
今天小編就為大家分享一篇layer ui 導(dǎo)入文件之前傳入數(shù)據(jù)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
JavaScript輸出當(dāng)前時(shí)間Unix時(shí)間戳的方法
這篇文章主要介紹了JavaScript輸出當(dāng)前時(shí)間Unix時(shí)間戳的方法,涉及javascript中Date及getTime等函數(shù)操作時(shí)間的使用技巧,需要的朋友可以參考下2015-04-04
非常好用的JsonToString 方法 簡(jiǎn)單實(shí)例
這篇文章介紹了非常好用的JsonToString簡(jiǎn)單實(shí)例,有需要的朋友可以參考一下2013-07-07
Autocomplete Textbox Example javascript實(shí)現(xiàn)自動(dòng)完成成功
Autocomplete Textbox Example javascript實(shí)現(xiàn)自動(dòng)完成成功...2007-08-08
swiperjs實(shí)現(xiàn)導(dǎo)航與tab頁(yè)的聯(lián)動(dòng)
這篇文章主要為大家詳細(xì)介紹了swiperjs實(shí)現(xiàn)導(dǎo)航與tab頁(yè)的聯(lián)動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
淺談JS獲取元素的N種方法及其動(dòng)靜態(tài)討論
這篇文章主要介紹了淺談JS獲取元素的N種方法及其動(dòng)靜態(tài)討論,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-08-08

