關(guān)于JS中的this

與其他語言相比忌愚,函數(shù)的 this 關(guān)鍵字在JavaScript中的行為略有不同吊档。它在嚴(yán)格模式和非嚴(yán)格模式之間也有一些區(qū)別判沟。
在絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了this的值恶导。this不能在執(zhí)行期間被賦值浆竭,在每次函數(shù)被調(diào)用時this的值也可能會不同。ES5引入了bind方法來設(shè)置函數(shù)的this值,而不用考慮函數(shù)如何被調(diào)用的邦泄。

全局上下文

  • 在全局運行上下文中(在任何函數(shù)體外部)删窒,this指代全局對象,無論是否在嚴(yán)格模式下顺囊。
console.log(this.document === document); // true
// 在瀏覽器中易稠,全局對象為 window 對象:
console.log(this === window); // true
this.a = 37;
console.log(window.a); // 37

函數(shù)上下文

  • 在函數(shù)內(nèi)部,this的值取決于函數(shù)是如何調(diào)用的包蓝。

1.直接調(diào)用
如果不是在嚴(yán)格模式下執(zhí)行驶社,并且this的值不會在函數(shù)執(zhí)行時被設(shè)置,此時的this的值會默認(rèn)設(shè)置為全局對象测萎。

function f1(){
  return this;
}

this === window; // true

然而亡电,在嚴(yán)格模式下,this將保持他進入執(zhí)行環(huán)境時的值硅瞧,所以直接調(diào)用的this將會默認(rèn)為undefined或者報錯

function f2(){
  "use strict"; // 這里是嚴(yán)格模式
  return this;
}

this === undefined; // true

2.對象方法中的 this
當(dāng)以對象里的方法的方式調(diào)用函數(shù)時份乒,它們的 this 是調(diào)用該函數(shù)的對象.

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); //  37

or

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37

3.原型鏈中的 this
相同的概念在定義在原型鏈中的方法也是一致的。如果該方法存在于一個對象的原型鏈上腕唧,那么this指向的是調(diào)用這個方法的對象或辖,表現(xiàn)得好像是這個方法就存在于這個對象上一樣。

var o = {
  f : function(){ 
    return this.a + this.b; 
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

4.getter 與 setter 中的 this
作為getter或setter函數(shù)都會綁定 this 到從設(shè)置屬性或得到屬性的那個對象枣接。

function modulus(){
  return Math.sqrt(this.re * this.re + this.im * this.im);
}

var o = {
  re: 1,
  im: -1,
  get phase(){
    return Math.atan2(this.im, this.re);
  }
};

Object.defineProperty(o, 'modulus', {
  get: modulus, enumerable:true, configurable:true});

console.log(o.phase, o.modulus); // logs -0.78 1.4142

5.構(gòu)造函數(shù)中的 this
當(dāng)一個函數(shù)被作為一個構(gòu)造函數(shù)來使用(使用new關(guān)鍵字)颂暇,它的this與即將被創(chuàng)建的新對象綁定。

var Obj = function (p) {
  this.p = p;
};

Obj.prototype.m = function() {
  return this.p;
};
var o = new Obj('Hello World!');

o.p // "Hello World!"
o.m() // "Hello World!"

call 和 apply但惶,bind 方法

  1. ECMAScript 5 引入了 Function.prototype.bind
    調(diào)用f.bind(someObject)會創(chuàng)建一個與f具有相同函數(shù)體和作用域的函數(shù)耳鸯,但是在這個新函數(shù)中,this將永久地被綁定到了bind的第一個參數(shù)膀曾,無論這個函數(shù)是如何被調(diào)用的县爬。
    bind比call方法和apply方法更進一步的是,除了綁定this以外添谊,還可以綁定原函數(shù)的參數(shù)财喳。
function.prototype.bind()
function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty

bind比call方法和apply方法更進一步的是,除了綁定this以外斩狱,還可以綁定原函數(shù)的參數(shù)耳高。

2.當(dāng)一個函數(shù)的函數(shù)體中使用了this關(guān)鍵字時,通過所有函數(shù)都從Function對象的原型中繼承的call()方法和apply()方法調(diào)用時喊废,它的值可以綁定到一個指定的對象上祝高。

call方法的參數(shù),應(yīng)該是一個對象污筷。如果參數(shù)為空、null和undefined,則默認(rèn)傳入全局對象瓣蛀。
var n = 123;
var obj = { n: 456 };

function a() {
  console.log(this.n);
}

a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456

call方法還可以接受多個參數(shù)
func.call(thisValue, arg1, arg2, ...)
call的第一個參數(shù)就是this所要指向的那個對象陆蟆,后面的參數(shù)則是函數(shù)調(diào)用時所需的參數(shù)。

3.function.prototype.apply()
apply方法的作用與call方法類似惋增,也是改變this指向叠殷,然后再調(diào)用該函數(shù)。唯一的區(qū)別就是诈皿,它接收一個數(shù)組作為函數(shù)執(zhí)行時的參數(shù)林束,使用格式如下。

func.apply(thisValue, [arg1, arg2, ...])

apply方法的第一個參數(shù)也是this所要指向的那個對象稽亏,如果設(shè)為null或undefined壶冒,則等同于指定全局對象。第二個參數(shù)則是一個數(shù)組截歉,該數(shù)組的所有成員依次作為參數(shù)胖腾,傳入原函數(shù)。原函數(shù)的參數(shù)瘪松,在call方法中必須一個個添加咸作,但是在apply方法中,必須以數(shù)組形式添加宵睦。

function f(x,y){
  console.log(x+y);
}

f.call(null,1,1) // 2
f.apply(null,[1,1]) // 2

DOM事件處理函數(shù)中的 this

  • 當(dāng)函數(shù)被用作事件處理函數(shù)時记罚,它的this指向觸發(fā)事件的元素(一些瀏覽器在使用非addEventListener的函數(shù)動態(tài)添加監(jiān)聽函數(shù)時不遵守這個約定)。
// 被調(diào)用時壳嚎,將關(guān)聯(lián)的元素變成藍色
function bluify(e){
  console.log(this === e.currentTarget); // 總是 true

  // 當(dāng) currentTarget 和 target 是同一個對象是為 true
  console.log(this === e.target);        
  this.style.backgroundColor = '#A5D9F3';
}

// 獲取文檔中的所有元素的列表
var elements = document.getElementsByTagName('*');

// 將bluify作為元素的點擊監(jiān)聽函數(shù)毫胜,當(dāng)元素被點擊時,就會變成藍色
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}

內(nèi)聯(lián)事件處理函數(shù)中的 this

  • 當(dāng)代碼被內(nèi)聯(lián)處理函數(shù)調(diào)用時诬辈,它的this指向監(jiān)聽器所在的DOM元素
<button onclick="alert(this.tagName.toLowerCase());">
  Show this
</button>

上面的alert會顯示button

其實酵使,幾句話就可以概括,實踐中記住這幾點就可以了焙糟,偷了幾句學(xué)霸的總結(jié):


this在函數(shù)執(zhí)行時才能確定口渔,JavaScript 中的 this 可以顯式的確定,比如通過call apply bind 以及尚未納入標(biāo)準(zhǔn)的函數(shù)綁定運算符::穿撮。 
確認(rèn)this具體是什么有三個辦法:

console.log(this)
source code, look for .call
API documentation
面試的時候缺脉,不能 log,沒有文檔悦穿,源碼又沒有用 call 之類的顯式的確定攻礼,就需要自己手動的轉(zhuǎn)換成fn.call(...)調(diào)用的方式來確定 this 
PS: 需要注意的是箭頭函數(shù)函數(shù)體內(nèi)的this,就是定義時所在的對象栗柒,而不是使用時所在的對象礁扮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子太伊,更是在濱河造成了極大的恐慌雇锡,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件僚焦,死亡現(xiàn)場離奇詭異锰提,居然都是意外死亡,警方通過查閱死者的電腦和手機芳悲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門立肘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人名扛,你說我怎么就攤上這事谅年。” “怎么了罢洲?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵踢故,是天一觀的道長。 經(jīng)常有香客問我惹苗,道長殿较,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任桩蓉,我火速辦了婚禮淋纲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘院究。我一直安慰自己洽瞬,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布业汰。 她就那樣靜靜地躺著伙窃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪样漆。 梳的紋絲不亂的頭發(fā)上为障,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音放祟,去河邊找鬼鳍怨。 笑死,一個胖子當(dāng)著我的面吹牛跪妥,可吹牛的內(nèi)容都是我干的鞋喇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼眉撵,長吁一口氣:“原來是場噩夢啊……” “哼侦香!你這毒婦竟也來了落塑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤鄙皇,失蹤者是張志新(化名)和其女友劉穎芜赌,沒想到半個月后仰挣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伴逸,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年膘壶,在試婚紗的時候發(fā)現(xiàn)自己被綠了错蝴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡颓芭,死狀恐怖顷锰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情亡问,我是刑警寧澤官紫,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站州藕,受9級特大地震影響束世,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜床玻,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一毁涉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锈死,春花似錦贫堰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至缨该,卻和暖如春偎行,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背压彭。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工睦优, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人壮不。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓汗盘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親询一。 傳聞我的和親對象是個殘疾皇子隐孽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容