網(wǎng)站首頁 編程語言 正文
如何通過一道題,全方位地考察自己,是否已經(jīng)完美掌握了:this指向、作用域&作用域鏈、閉包、特殊數(shù)據(jù)類型?
作者:拯救世界的光太郎 更新時間: 2022-02-17 編程語言inner = 'window';
function say() {
console.log(inner);
console.log(this.inner);
}
var obj1 = (function() {
var inner = '1-1';
return {
inner: '1-2',
say: function() {
console.log(inner);
console.log(this.inner);
}
}
})();
var obj2 = (function() {
var inner = '2-1';
return {
inner: '2-2',
say: function() {
console.log(inner);
console.log(this.inner);
}
}
})();
say();
obj1.say();
obj2.say();
obj1.say = say;
obj1.say();
obj1.say = obj2.say;
obj1.say();
蠻有意思的一道題,在對照答案之前,一定要先自己分析一下每一步的執(zhí)行結(jié)果!
// 答案:
window
window
1-1
1-2
2-1
2-2
window
1-2
2-1
1-2
我們按照順序一個一個來分析
? ?1.?say();
inner = 'window';
function say() {
console.log(inner); // window
console.log(this.inner); // window
}
say();
直接為 inner 賦值,那么就相當(dāng)于為 window 對象添加一個 inner 屬性,并賦值
函數(shù)被直接調(diào)用,等價于由 window 來調(diào)用 say 函數(shù),say() →?window.say()。所以 say 函數(shù)體內(nèi) this 也就指向 window,也就是函數(shù)體內(nèi)的 this.inner →?window.inner。
直接訪問 inner 屬性時,先在函數(shù)體內(nèi)尋找該屬性,沒有,就向上一層作用域?qū)ふ遥谌肿饔糜蛑姓业搅嗽搶傩裕蛴 ?/p>
? ?2.?obj1.say();
var obj1 = (function() {
console.log( '1: ', this ); // 1: Window{window: Window,...}
var inner = '1-1';
return {
inner: '1-2',
say: function() {
console.log( '2: ', this ); // 2: {inner: '1-2', say: ?}
console.log('3: ', inner); // 3: 1-1
console.log('4: ', this.inner); // 4: 1-2
}
}
})();
obj1.say();
首先,分析 obj1,obj1 保存一個自調(diào)用的匿名函數(shù)(IIFE),IIFE的調(diào)用者是 window,所以函數(shù)體內(nèi)打印的 this 自然就是一個 Window 類型的對象。
2 處打印的 this 也很容易理解,obj1 等于被 return 的對象 { inner: '1-2', say: function(){...} } ,obj1 調(diào)用 say 方法,也就相當(dāng)于 { inner: '1-2', say: function(){...} } 調(diào)用 say 方法,所以打印的 this 自然也就是這個對象了。
3 處打印 inner,say 函數(shù)體中沒有 inner 屬性,向上層尋找,這個 “上層” ,指代的是上層作用域,可以產(chǎn)生作用域的語句包括 if、while、switch 等判斷、循環(huán)語句,以及函數(shù)。也就是說,對象是不會產(chǎn)生作用域的,因此,say 函數(shù)體的上層作用域,其實對應(yīng)的是外層的匿名函數(shù) 函數(shù)體。那么直接打印 inner,找到的也就是在匿名函數(shù)中通過 var 定義的 inner 屬性。
4 處很簡單,上面我們已經(jīng)分析過對象中 say 函數(shù)的 this 指向,這里打印 this.inner 也就可以很直觀的看出來,也就等價于 { inner: '1-2', say: function(){...} }.inner。
? ?3.?obj2.say();
它和內(nèi)部的代碼和 obj1.say() 沒有實質(zhì)性的區(qū)別,分析方法和上面是一樣的。
? ?4.?obj1.say = say; obj1.say();
為了提升代碼整體的可讀性,我們對代碼進行一個小小的調(diào)整
inner = 'window';
function say() {
console.log('1: ', inner); // 1: window
console.log('2: ', this.inner); // 2: 1-2
}
var obj1 = (function() {
var inner = '1-1';
return {
inner: '1-2',
say: function() {
console.log('3: ', inner);
console.log('4: ', this.inner);
}
}
})();
obj1.say = say;
obj1.say();
這里考察的核心,其實就只有一點,就是函數(shù)究竟屬于什么類型?
如果可以肯定答案是引用類型,那么恭喜你,這道題基本已經(jīng)被你攻破了!
這么一來,我們就可以確定,對 obj1.say 進行重新賦值后,通過 obj1.say() 調(diào)用的say函數(shù),就應(yīng)該是調(diào)用的全局作用域中的 say 函數(shù)。
能把這一點分析出來,基本上這道題最難的點就已經(jīng)被我們拿下了。
把上面的點分析出來后,千萬不能迷糊!我們是調(diào)用全局作用域中的 say 方法,并不是把全局作用域的 say 方法放到 obj1 里面。
分析出來上一點后,下面就是常規(guī)的套路,函數(shù)體內(nèi)沒有 inner,就去上一層作用域中查找,找到了全局作用域中的 inner。
由 obj1 調(diào)用的say方法,那么 this 就指向 obj1,this.inner 自然就是 { inner: '1-2', say: function() {...} } 對象的 inner 屬性。
? ?5.?obj1.say = obj2.say; obj1.say();
var obj1 = (function() {
var inner = '1-1';
return {
inner: '1-2',
say: function() {
console.log('1: ', inner);
console.log('2: ', this.inner);
}
}
})();
var obj2 = (function() {
var inner = '2-1';
return {
inner: '2-2',
say: function() {
console.log('3: ', inner); // 3: 2-1
console.log('4: ', this.inner); // 4: 1-2
}
}
})();
obj1.say = obj2.say;
obj1.say();
這個時候,在來看這一題,是不是就發(fā)現(xiàn)太簡單了。
把 obj2 中的 say 方法賦給 obj1 的 say 屬性,前面已經(jīng)說過了,函數(shù)是引用類型。那么,在賦值后,我們通過 obj1.say() 調(diào)用的 say 方法,依舊是 obj2 的 say 方法。因此直接打印 inner 屬性時,向上層尋找,找的是 obj2 指向的匿名函數(shù)體的上下文,打印的自然就是 2-1。
由于是 obj1 調(diào)用的 say 方法,那么 this 指向的也是 obj1 中被返回的對象:{ inner: '1-2', say: function() {...} },所以打印出來的自然也就是 1-2 了。
原文鏈接:https://blog.csdn.net/qq_44647809/article/details/121694612
相關(guān)推薦
- 2022-09-20 一文詳解C++中動態(tài)內(nèi)存管理_C 語言
- 2022-09-01 C語言中的程序環(huán)境與預(yù)處理詳情_C 語言
- 2023-02-02 redis中的配置以及密碼設(shè)置方式_Redis
- 2022-06-06 ceph集群RadosGW對象存儲使用詳解_其它綜合
- 2022-12-21 Python?eval()和exec()函數(shù)使用詳解_python
- 2022-11-16 Kotlin擴展方法超詳細介紹_Android
- 2022-03-30 C語言關(guān)鍵字之a(chǎn)uto?register詳解_C 語言
- 2022-12-13 sql索引失效的情況以及超詳細解決方法_MsSql
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支