JavaScript中的this關(guān)鍵字用法詳解
先舉一個(gè)生活例子:
小明正在跑步,他看起來(lái)很開(kāi)心
這里的小明是主語(yǔ),如果沒(méi)有這個(gè)主語(yǔ),那么后面的代詞『他』將毫無(wú)意義。有了主語(yǔ),代詞才有了可以指代的事物。
類比到JavaScript的世界中,我們?cè)谡{(diào)用一個(gè)對(duì)象的方法的時(shí)候,需要先指明這個(gè)對(duì)象,再指明要調(diào)用的方法。
var xiaoming = { name: 'Xiao Ming', run: function() { console.log(`${this.name} seems happy`); }, }; xiaoming.run();
在上面的例子中,第8行中的xiaoming
指定了run
方法運(yùn)行時(shí)的主語(yǔ)。因此,在run
中,我們才可以用this
來(lái)代替xiaoming
這個(gè)對(duì)象??梢钥吹?code>this起了代詞的作用。
同樣的,對(duì)于一個(gè)JavaScript類,在將它初始化之后,我們也可以用類似的方法來(lái)理解:類的實(shí)例在調(diào)用其方法的時(shí)候,將作為主語(yǔ),其方法中的this
就自然變成了指代主語(yǔ)的代詞。
class People { constructor(name) { // 在用new關(guān)鍵字實(shí)例化一個(gè)對(duì)象的時(shí)候,相當(dāng)于在說(shuō), // “創(chuàng)建一個(gè)People類實(shí)例(主語(yǔ)),它(this)的name是……” // 所以這里的this就是新創(chuàng)建的People類實(shí)例 this.name = name; } run() { console.log(`${this.name} seems happy.`) } } // new關(guān)鍵字實(shí)例化一個(gè)類 var xiaoming = new People('xiaoming'); xiaoming.run();
這就是我認(rèn)為this關(guān)鍵字設(shè)計(jì)得精彩的地方!如果將調(diào)用方法的語(yǔ)句var xiaoming = new People('xiaoming');
和方法本身的代碼連起來(lái),像英語(yǔ)一樣讀,其實(shí)是完全通順的。
this的綁定
句子的主語(yǔ)是可以變的,例如在下面的場(chǎng)景中,run
被賦值到小芳(xiaofang
)身上之后,調(diào)用xiaofang.run
,主語(yǔ)就變成了小芳!
var xiaofang = { name: 'Xiao Fang', }; var xiaoming = { name: 'Xiao Ming', run: function() { console.log(`${this.name} seems happy`); }, }; xiaofang.run = xiaoming.run; // 主語(yǔ)變成了小芳 xiaofang.run();
但是如果小明很摳門(mén),不愿意將run
方法借給小芳以后,this
就變成了小芳的話,那么小明要怎么做呢?他可以通過(guò)Function.prototype.bind讓run
運(yùn)行時(shí)候的this
永遠(yuǎn)為小明自己。
var xiaofang = { name: 'Xiao Fang', }; var xiaoming = { name: 'Xiao Ming', run: function() { console.log(`${this.name} seems happy`); }, }; // 將小明的run方法綁定(bind)后,返回的還是一個(gè) // 函數(shù),但是這個(gè)函數(shù)之后被調(diào)用的時(shí)候就算主語(yǔ)不是小明, // 它的this依然是小明 xiaoming.run = xiaoming.run.bind(xiaoming); xiaofang.run = xiaoming.run; // 主語(yǔ)雖然是小芳,但是最后this還是小明 xiaofang.run();
那么同一個(gè)函數(shù)被多次bind
之后,到底this
是哪一次bind
的對(duì)象呢?你可以自己嘗試看看。
call與apply
Function.prototype.call
允許你在調(diào)用一個(gè)函數(shù)的時(shí)候指定它的this
的值。
var xiaoming = { name: 'Xiao Ming' }; function run(today, mood) { console.log(`Today is ${today}, ${this.name} seems ${mood}`); } // 函數(shù)的call方法第一個(gè)參數(shù)是this的值 // 后續(xù)只需按函數(shù)參數(shù)的順序傳參即可 run.call(xiaoming, 'Monday', 'happy')
Function.prototype.apply
和Function.prototype.call
的功能是一模一樣的,區(qū)別進(jìn)在于,apply
里將函數(shù)調(diào)用所需的所有參數(shù)放到一個(gè)數(shù)組當(dāng)中。
var xiaoming = { name: 'Xiao Ming' }; function run(today, mood) { console.log(`Today is ${today}, ${this.name} seems ${mood}`); } // apply只接受兩個(gè)參數(shù) // 第二個(gè)參數(shù)是一個(gè)數(shù)組,這個(gè)數(shù)組的元素被按順序 // 作為run調(diào)用的參數(shù) run.apply(xiaoming, ['Monday', 'happy'])
那么call
/apply
和上面的bind
混用的時(shí)候是什么樣的行為呢?這個(gè)也留給大家自行驗(yàn)證。但是在一般情況下,我們應(yīng)該避免混用它們,否則會(huì)造成代碼檢查或者調(diào)試的時(shí)候難以跟蹤this
的值的問(wèn)題。
當(dāng)方法失去主語(yǔ)的時(shí)候,this不再有?
其實(shí)大家可以發(fā)現(xiàn)我的用詞,當(dāng)一個(gè)function
被調(diào)用的時(shí)候是有主語(yǔ)的時(shí)候,它是一個(gè)方法;當(dāng)一個(gè)function
被調(diào)用的時(shí)候是沒(méi)有主語(yǔ)的時(shí)候,它是一個(gè)函數(shù)。當(dāng)一個(gè)函數(shù)運(yùn)行的時(shí)候,它雖然沒(méi)有主語(yǔ),但是它的this
的值會(huì)是全局對(duì)象。在瀏覽器里,那就是window
。當(dāng)然了,前提是函數(shù)沒(méi)有被bind
過(guò),也不是被apply
或call
所調(diào)用。
那么function
作為函數(shù)的情景有哪些呢?
首先,全局函數(shù)的調(diào)用就是最簡(jiǎn)單的一種。
function bar() { console.log(this === window); // 輸出:true } bar();
立即調(diào)用的函數(shù)表達(dá)式(IIFE,Immediately-Invoked Function Expression)也是沒(méi)有主語(yǔ)的,所以它被調(diào)用的時(shí)候this
也是全局對(duì)象。
(function() { console.log(this === window); // 輸出:true })();
但是,當(dāng)函數(shù)被執(zhí)行在嚴(yán)格模式(strict-mode)下的時(shí)候,函數(shù)的調(diào)用時(shí)的this就是undefined
了。這是很值得注意的一點(diǎn)。
function bar() { 'use strict'; console.log('Case 2 ' + String(this === undefined)); // 輸出:undefined } bar();
不可見(jiàn)的調(diào)用
有時(shí)候,你沒(méi)有辦法看到你定義的函數(shù)是怎么被調(diào)用的。因此,你就沒(méi)有辦法知道它的主語(yǔ)。下面是一個(gè)用jQuery添加事件監(jiān)聽(tīng)器的例子。
window.val = 'window val'; var obj = { val: 'obj val', foo: function() { $('#text').bind('click', function() { console.log(this.val); }); } }; obj.foo();
在事件的回調(diào)函數(shù)(第6行開(kāi)始定義的匿名函數(shù))里面,this
的值既不是window
,又不是obj
,而是頁(yè)面上id
為text
的HTML元素。
var obj = { foo: function() { $('#text').bind('click', function() { console.log(this === document.getElementById('text')); // 輸出:true }); } }; obj.foo();
這是因?yàn)槟涿瘮?shù)是被jQuery內(nèi)部調(diào)用的,我們不知道它調(diào)用的時(shí)候的主語(yǔ)是什么,或者是否被bind
等函數(shù)修改過(guò)this
的值。所以,當(dāng)你將匿名函數(shù)交給程序的其他部分調(diào)用的時(shí)候,需要格外地謹(jǐn)慎。
如果我們想要在上面的回調(diào)函數(shù)里面使用obj的val
值,除了直接寫(xiě)obj.val
之外,還可以在foo方法中用一個(gè)新的變量that
來(lái)保存foo
運(yùn)行時(shí)this
的值。這樣說(shuō)有些繞口,我們看下例子便知。
window.val = 'window val'; var obj = { val: 'obj val', foo: function() { var that = this; // 保存this的引用到that,這里的this實(shí)際上就是obj $('#text').bind('click', function() { console.log(that.val); // 輸出:obj val }); } }; obj.foo();
另外一種方法就是為該匿名函數(shù)bind
了。
window.val = 'window val'; var obj = { val: 'obj val', foo: function() { $('#text').bind('click', function() { console.log(this.val); // 輸出:obj val }.bind(this)); } }; obj.foo();
總結(jié)
在JavaScript中this
的用法的確是千奇百怪,但是如果利用自然語(yǔ)言的方式來(lái)理解,一切就順理成章了。不知道你讀完這篇文章的時(shí)候理解了嗎?
以上就是JavaScript中的this關(guān)鍵字用法詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript this關(guān)鍵字的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript正則函數(shù)中test和match的區(qū)別解析
在javascript中,用于檢測(cè)一個(gè)字符串是否匹配某個(gè)模式用的比較多的就是test和match方法。,這篇文章主要介紹了js正則函數(shù)中test和match的區(qū)別,需要的朋友可以參考下2022-11-11javascript的replace方法結(jié)合正則使用實(shí)例總結(jié)
這篇文章主要介紹了javascript的replace方法結(jié)合正則使用技巧,實(shí)例總結(jié)了replace方法配合正則表達(dá)式進(jìn)行變量、分組、字符等替換技巧,需要的朋友可以參考下2016-06-06IE6-IE9中tbody的innerHTML不能賦值的解決方法
這篇文章主要介紹了IE6-IE9中tbody的innerHTML不能賦值的解決方法,需要的朋友可以參考下2014-06-06推薦幾個(gè)不錯(cuò)的console調(diào)試技巧實(shí)現(xiàn)
這篇文章主要介紹了推薦幾個(gè)不錯(cuò)的console調(diào)試技巧實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12使用js操作css實(shí)現(xiàn)js改變背景圖片示例
有個(gè)朋友在weibo上問(wèn)我可不可以用JS和CSS讓頁(yè)面每次刷新隨機(jī)產(chǎn)生一張背景圖,當(dāng)然是可以的。具體的方法看下面的實(shí)現(xiàn)代碼吧2014-03-03微信瀏覽器左上角返回按鈕監(jiān)聽(tīng)的實(shí)現(xiàn)
這篇文章主要介紹了微信瀏覽器左上角返回按鈕監(jiān)聽(tīng)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03JavaScript數(shù)組Array對(duì)象增加和刪除元素方法總結(jié)
這篇文章主要介紹了JavaScript數(shù)組Array對(duì)象增加和刪除元素方法,實(shí)例總結(jié)了pop方法、push方法、splice方法、concat方法等的使用技巧,需要的朋友可以參考下2015-01-01