JavaScript中的this關(guān)鍵字用法詳解
先舉一個生活例子:
小明正在跑步,他看起來很開心
這里的小明是主語,如果沒有這個主語,那么后面的代詞『他』將毫無意義。有了主語,代詞才有了可以指代的事物。
類比到JavaScript的世界中,我們在調(diào)用一個對象的方法的時(shí)候,需要先指明這個對象,再指明要調(diào)用的方法。
var xiaoming = {
name: 'Xiao Ming',
run: function() {
console.log(`${this.name} seems happy`);
},
};
xiaoming.run();在上面的例子中,第8行中的xiaoming指定了run方法運(yùn)行時(shí)的主語。因此,在run中,我們才可以用this來代替xiaoming這個對象??梢钥吹?code>this起了代詞的作用。
同樣的,對于一個JavaScript類,在將它初始化之后,我們也可以用類似的方法來理解:類的實(shí)例在調(diào)用其方法的時(shí)候,將作為主語,其方法中的this就自然變成了指代主語的代詞。
class People {
constructor(name) {
// 在用new關(guān)鍵字實(shí)例化一個對象的時(shí)候,相當(dāng)于在說,
// “創(chuàng)建一個People類實(shí)例(主語),它(this)的name是……”
// 所以這里的this就是新創(chuàng)建的People類實(shí)例
this.name = name;
}
run() {
console.log(`${this.name} seems happy.`)
}
}
// new關(guān)鍵字實(shí)例化一個類
var xiaoming = new People('xiaoming');
xiaoming.run();這就是我認(rèn)為this關(guān)鍵字設(shè)計(jì)得精彩的地方!如果將調(diào)用方法的語句var xiaoming = new People('xiaoming');和方法本身的代碼連起來,像英語一樣讀,其實(shí)是完全通順的。
this的綁定
句子的主語是可以變的,例如在下面的場景中,run被賦值到小芳(xiaofang)身上之后,調(diào)用xiaofang.run,主語就變成了小芳!
var xiaofang = {
name: 'Xiao Fang',
};
var xiaoming = {
name: 'Xiao Ming',
run: function() {
console.log(`${this.name} seems happy`);
},
};
xiaofang.run = xiaoming.run;
// 主語變成了小芳
xiaofang.run();但是如果小明很摳門,不愿意將run方法借給小芳以后,this就變成了小芳的話,那么小明要怎么做呢?他可以通過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)后,返回的還是一個
// 函數(shù),但是這個函數(shù)之后被調(diào)用的時(shí)候就算主語不是小明,
// 它的this依然是小明
xiaoming.run = xiaoming.run.bind(xiaoming);
xiaofang.run = xiaoming.run;
// 主語雖然是小芳,但是最后this還是小明
xiaofang.run();那么同一個函數(shù)被多次bind之后,到底this是哪一次bind的對象呢?你可以自己嘗試看看。
call與apply
Function.prototype.call允許你在調(diào)用一個函數(shù)的時(shí)候指定它的this的值。
var xiaoming = {
name: 'Xiao Ming'
};
function run(today, mood) {
console.log(`Today is ${today}, ${this.name} seems ${mood}`);
}
// 函數(shù)的call方法第一個參數(shù)是this的值
// 后續(xù)只需按函數(shù)參數(shù)的順序傳參即可
run.call(xiaoming, 'Monday', 'happy')Function.prototype.apply和Function.prototype.call的功能是一模一樣的,區(qū)別進(jìn)在于,apply里將函數(shù)調(diào)用所需的所有參數(shù)放到一個數(shù)組當(dāng)中。
var xiaoming = {
name: 'Xiao Ming'
};
function run(today, mood) {
console.log(`Today is ${today}, ${this.name} seems ${mood}`);
}
// apply只接受兩個參數(shù)
// 第二個參數(shù)是一個數(shù)組,這個數(shù)組的元素被按順序
// 作為run調(diào)用的參數(shù)
run.apply(xiaoming, ['Monday', 'happy'])那么call/apply和上面的bind混用的時(shí)候是什么樣的行為呢?這個也留給大家自行驗(yàn)證。但是在一般情況下,我們應(yīng)該避免混用它們,否則會造成代碼檢查或者調(diào)試的時(shí)候難以跟蹤this的值的問題。
當(dāng)方法失去主語的時(shí)候,this不再有?
其實(shí)大家可以發(fā)現(xiàn)我的用詞,當(dāng)一個function被調(diào)用的時(shí)候是有主語的時(shí)候,它是一個方法;當(dāng)一個function被調(diào)用的時(shí)候是沒有主語的時(shí)候,它是一個函數(shù)。當(dāng)一個函數(shù)運(yùn)行的時(shí)候,它雖然沒有主語,但是它的this的值會是全局對象。在瀏覽器里,那就是window。當(dāng)然了,前提是函數(shù)沒有被bind過,也不是被apply或call所調(diào)用。
那么function作為函數(shù)的情景有哪些呢?
首先,全局函數(shù)的調(diào)用就是最簡單的一種。
function bar() {
console.log(this === window); // 輸出:true
}
bar();立即調(diào)用的函數(shù)表達(dá)式(IIFE,Immediately-Invoked Function Expression)也是沒有主語的,所以它被調(diào)用的時(shí)候this也是全局對象。
(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();不可見的調(diào)用
有時(shí)候,你沒有辦法看到你定義的函數(shù)是怎么被調(diào)用的。因此,你就沒有辦法知道它的主語。下面是一個用jQuery添加事件監(jiān)聽器的例子。
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行開始定義的匿名函數(shù))里面,this的值既不是window,又不是obj,而是頁面上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í)候的主語是什么,或者是否被bind等函數(shù)修改過this的值。所以,當(dāng)你將匿名函數(shù)交給程序的其他部分調(diào)用的時(shí)候,需要格外地謹(jǐn)慎。
如果我們想要在上面的回調(diào)函數(shù)里面使用obj的val值,除了直接寫obj.val之外,還可以在foo方法中用一個新的變量that來保存foo運(yùn)行時(shí)this的值。這樣說有些繞口,我們看下例子便知。
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的用法的確是千奇百怪,但是如果利用自然語言的方式來理解,一切就順理成章了。不知道你讀完這篇文章的時(shí)候理解了嗎?
以上就是JavaScript中的this關(guān)鍵字用法詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript this關(guān)鍵字的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript DOM編程實(shí)例(智播客學(xué)習(xí))
最近一直在努力學(xué)習(xí)DOM編程這塊,這是目前成就感最強(qiáng)烈的一塊了,畢老師很認(rèn)真的給我們講解了相關(guān)知識,并在網(wǎng)上找了很多做的非常棒的網(wǎng)頁作為例程給我們進(jìn)行講解2009-11-11
Selenium執(zhí)行JavaScript腳本的方法示例
這篇文章主要介紹了Selenium執(zhí)行JavaScript腳本的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
echarts浮動顯示單位的實(shí)現(xiàn)方法示例
這篇文章主要給大家介紹了關(guān)于echarts浮動顯示單位的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
微信小程序?qū)崿F(xiàn)下載進(jìn)度條的方法
本篇文章主要介紹了微信小程序?qū)崿F(xiàn)下載進(jìn)度條的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12
一文帶你理解微信小程序中RPC通信的實(shí)現(xiàn)
在微信小程序開發(fā)中,要實(shí)現(xiàn)兩個線程之間的通信是一項(xiàng)重要的任務(wù),所以本文就來講講如何使用小程序的?postMessage?和?addListener?API?來實(shí)現(xiàn)在兩個線程之間進(jìn)行高效的?RPC?通信吧2023-06-06
elementui?日歷組件el-calendar使用總結(jié)
這篇文章主要介紹了elementui?日歷組件el-calendar使用總結(jié),引用dayjs處理日期,結(jié)合el-calendar完美實(shí)現(xiàn),需要的朋友可以參考下2024-07-07

