javascript的this關(guān)鍵字詳解
this 的定義
表示當(dāng)前執(zhí)行代碼的環(huán)境對(duì)象
因此可將 this 的剖析分為“全局環(huán)境” 和 “函數(shù)環(huán)境” 兩種類型的環(huán)境對(duì)象
全局環(huán)境
console.log(this === window); // true var a = 10; console.log(this.a); // 10
函數(shù)環(huán)境
在函數(shù)內(nèi)部,this 的取值取決于函數(shù)被調(diào)用時(shí)的運(yùn)行環(huán)境。
這里涉及到內(nèi)存里的數(shù)據(jù)結(jié)構(gòu)相關(guān)的知識(shí)點(diǎn),當(dāng)我們定義以下字面量對(duì)象時(shí)會(huì)發(fā)生一系列的關(guān)聯(lián)關(guān)系
var obj = { name: 'Tom' };
javascript 引擎會(huì)先在內(nèi)存中生成 { name: 'Tom' } 對(duì)象,接著再把這個(gè)對(duì)象的內(nèi)存地址賦值給 obj 變量,所以 obj 變量保存的只是一個(gè)內(nèi)存地址而已,如果要獲取 obj.name,javascript 引擎會(huì)先從 obj 變量中拿到內(nèi)存地址,然后從該地址中獲取原始對(duì)象,再返回 name 屬性。
而屬性值為函數(shù)時(shí),該函數(shù)會(huì)被保存在內(nèi)存中,然后將該內(nèi)存地址賦值給該屬性,因此該地址賦值給不同環(huán)境執(zhí)行時(shí)它的作用域是不一樣的,而 this 對(duì)象就是指向函數(shù)當(dāng)前的執(zhí)行環(huán)境對(duì)象,執(zhí)行環(huán)境是會(huì)在 Event Loop(事件循環(huán))過程中變化的,因此 this 在函數(shù)環(huán)境下是屬于運(yùn)行時(shí)的。
var name = 'Tom'; var obj = { name: 'Iceberg', say: function() { console.log('my name is ' + this.name); }, sub: { say: function() { console.log('my name is ' + this.name); } } }; obj.say(); // my name is Iceberg obj.sub.say() // my name is undefined; var say = obj.say; say(); // my name is Tom;
上面的例子說明 obj.say() 執(zhí)行環(huán)境為 obj 對(duì)象,而 obj.sub.say() 的執(zhí)行環(huán)境卻是 obj.sub 對(duì)象,而對(duì)于 obj.sub 來說并沒有 name 屬性,因此為 undefined;而 var say = obj.say; 則表示將 say 方法的內(nèi)存地址賦值給全局變量,因此從全局變量 name 中取值。
運(yùn)用場(chǎng)景
接下來從 this 在函數(shù)環(huán)境下的不同運(yùn)用場(chǎng)景來剖析
事件回調(diào)函數(shù)
var handler = { nickname: 'anonymous', register: function() { console.log(this.nickname); } } $('#registerBtn').on('click', handler.register); // undefined
以上邏輯點(diǎn)擊觸發(fā)后輸出的是 undefined,因?yàn)楹瘮?shù)被當(dāng)做事件觸發(fā)的回調(diào)函數(shù)執(zhí)行時(shí),this 是指向該觸發(fā)事件對(duì)應(yīng)的元素,如要 this 仍然以 handler 對(duì)象為執(zhí)行環(huán)境,則可使用函數(shù)的 bind 方法進(jìn)行執(zhí)行環(huán)境對(duì)象的綁定操作。
$('#registerBtn').on('click', handler.register.bind(handler)); // anonymous
在 react 中經(jīng)常需要在回調(diào)函數(shù)中調(diào)用 this.state、this.props,按照上面的分析,將當(dāng)前環(huán)境對(duì)象 bind 到回調(diào)函數(shù)中即可。
如果是使用的箭頭函數(shù)定義回調(diào)函數(shù)即可無需 bind,因?yàn)榧^函數(shù)中 this 就是對(duì)應(yīng)定義時(shí)所在的對(duì)象。
構(gòu)造函數(shù)
要理解 this 在構(gòu)造函數(shù)中的邏輯就要理清楚構(gòu)造函數(shù)在實(shí)例化過程中都發(fā)生了什么。
function A() { this.name = 'Tom'; this.age = 20; } var a = new A();
使用 new 命令實(shí)例化構(gòu)造函數(shù) A 的過程中會(huì)發(fā)生以下流程
- 創(chuàng)建一個(gè)空對(duì)象,作為將要返回的對(duì)象實(shí)例
- 將該空對(duì)象的原型指向構(gòu)造函數(shù)的 prototype 屬性
- 將該空對(duì)象賦值給構(gòu)造函數(shù)內(nèi)部的 this 關(guān)鍵字
- 執(zhí)行構(gòu)造函數(shù)內(nèi)部代碼
- 默認(rèn)返回 this 對(duì)象(如 return 的為非對(duì)象類型,如數(shù)字 123,會(huì)被忽略進(jìn)而默認(rèn) return this 對(duì)象)
- 由以上邏輯可知道 this 關(guān)鍵字在構(gòu)造函數(shù)中表示的是其實(shí)例對(duì)象。
bind
bind 方法將函數(shù)體中的 this 指向新對(duì)象并返回一個(gè)新函數(shù)
function A() { this.nickname = 'Tom'; this.say = function() { console.log(this.nickname); } } var b = { nickname: 'John' }; var a = new A(); var say = a.say; var say1 = a.say.bind(a); var say2 = a.say.bind(b); say(); // undefined say1(); // Tom say2(); // John
call & apply
call 方法是指 Function.prototype.call,因此每個(gè)函數(shù)都會(huì)具備 call 方法,fun.call(thisArg, arg1, arg2, ...),call 方法接收的第一個(gè)參數(shù)會(huì)替換原有的 this 指向的執(zhí)行環(huán)境對(duì)象。
function A() { this.name = 'Tom'; this.sayName = function(){ console.log(this.name); }; } function B() { this.name = 'John'; } var a = new A(); a.sayName.call(new B()); // John
而 apply 方法與 call 的區(qū)別僅在于 call 接收參數(shù)列表而 apply 接收數(shù)組參數(shù)或者類數(shù)組對(duì)象(如函數(shù)的 arguments 對(duì)象)。
總結(jié)
由于 javascript 的 Event Loop 原理,決定了執(zhí)行上下文會(huì)不斷變化,因此 this 對(duì)象誕生于表達(dá)當(dāng)前的執(zhí)行環(huán)境對(duì)象。
以上所述是小編給大家介紹的javascript的this關(guān)鍵字的用法詳解整合,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
javaScript給元素添加多個(gè)class的簡(jiǎn)單實(shí)現(xiàn)
下面小編就為大家?guī)硪黄猨avaScript給元素添加多個(gè)class的簡(jiǎn)單實(shí)現(xiàn)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-07-07微信小程序?qū)崿F(xiàn)獲取用戶信息替換用戶名和頭像到首頁
本文詳細(xì)講解了微信小程序?qū)崿F(xiàn)獲取用戶信息替換用戶名和頭像到首頁的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06javascript 主動(dòng)派發(fā)事件總結(jié)
有時(shí)需要模仿用戶的一些動(dòng)作(鼠標(biāo)/鍵盤操作),最常見的莫過于鼠標(biāo)點(diǎn)擊。一一列舉2011-08-08js實(shí)現(xiàn)表格拖動(dòng)選項(xiàng)
這篇文章主要為大家詳細(xì)介紹了原生js實(shí)現(xiàn)表格拖動(dòng)選項(xiàng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04微信小程序使用swiper組件實(shí)現(xiàn)類3D輪播圖
在寫微信小程序時(shí),有寫到實(shí)現(xiàn)3D輪播圖的效果,可以直接使用微信小程序中自帶的組件swiper來實(shí)現(xiàn)。下面通過實(shí)例代碼給大家介紹微信小程序輪播圖的實(shí)現(xiàn)方法,感興趣的朋友一起看看吧2018-08-08layui form.render(''select'', ''test2'') 更新渲染的方法
今天小編就為大家分享一篇layui form.render('select', 'test2') 更新渲染的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09