談談程式碼中的this
js中我們常常會遇到this,this的具體指向問題對於很多同學來說是很懵懂的;就想lz剛開始接觸時候就是一臉的懵逼,經常被一些題目轉的眼花繚亂。那麼今天lz就跟大家一起交流一下這個this的指向問題!
背景:不久前有個同事給我們發了一道有關this的題目,於是便有了今天的故事。如下題:
class D0XX { constructor () { this.attr = {}; } init (config) { this.assign(config) return this; } assign (config) {this.attr.afterClose = config.afterClose; } close(){ if(typeof this.attr.afterClose === 'function'){ this.attr.afterClose(); } } } class T0XX{ init(){ this.openPop() } openPop(){ new D0XX().init({ afterClose(){ console.log(this) } }).close() } } new T0XX().init(); //請問打印出結果是什麼?
一、且擱下此題目,我們先談談this的指向的以下幾個情況;
1.1.指向全域性物件上;
我們在一般的函式呼叫中的this是直接指向我們的全域性物件的,比如:
function globalThis(){ console.log(this.name);//今天天氣真冷哇 } var name = '今天天氣真冷哇' globalThis(); setTimeout(function(){ console.log(this.name2); },1000); var name2 = '過了一秒鐘,我就更冷了'
這裡的setTimeout裡面的this是指向window物件的!
1.2.指向上文物件
通俗點就是,哪個物件看上了我,我就跟誰,比如:
function foo() { console.log(this.a); } var obj = { a: '李四', foo: foo } var a = '張三'; obj.foo(); //李四 看前面是哪個物件(obj),於是this跟obj一見鍾情就好上了 var bar = obj.foo; bar();//張三 你以為的以為。。 前面說過看物件,沒物件,那就只能全域性物件上茫茫人海只為尋她
1.3.指向那個‘類’
我們一般用建構函式進行呼叫時,會產生一個this始終是指向這個‘類’,我們複習下new 一個物件發生了什麼:
1.建立一個全新的物件。
2.這個物件會被執行[[Prototype]]連線。
3.這個新物件會繫結到函式呼叫的this
。
4.執行這個函式裡的程式碼。
5.如果函式沒有返回其他物件,則自動返回這個新物件。
function fun() { this.a = 1; this.b = 2; } var instance = new fun(); console.log(instance.a);//1
1.4.箭頭函式this指向當前作用域
箭頭函式this指向取決於外層的函式作用域或全域性作用域,而且箭頭函式的繫結無法修改,即使是new
繫結也不可以。
document.onclick = ()=>{ console.log(this) //window } document.onclick=function(){ console.log(this) //document }
二、如何改變this的繫結關係
2.1.顯式繫結
在此之前,相信你已經用過很多次apply
和call、
bind函數了,使用這三個函式可以直接為你要執行的函式指定this
,所以這種方式稱為顯式繫結。
function foo () { console.log(this.a) } var obj = { a: 2 } foo.call(obj) // 2 function foo (something) { console.log(this.a, something) return this.a + something } var obj = { a: 2 } var bar = foo.bind(obj); // bind返回一個繫結到obj上的新函式 var b = bar(3) console.log(b) var a = "window's a" foo('!')
如上就可以通過這種顯式的方法進行改變繫結關係了;
三、迴歸到之前同事的題目上
通過以上的分析,我們就能夠很清楚的分析出以上的答案是指向this.attr這個物件的,別看題目裡又有new字元又有return this;這些東西,很容易讓人迷糊;但是如果我們能掌握住this的這幾種指向情況,相信會易容反掌的多;
四、如果改動以上的題目你還知道麼?
class D0XX { constructor () { this.attr = {} } init (config) { this.assign(config) return this } assign (config) { this.afterClose = config.afterClose } close(){ if(typeof this.afterClose === 'function'){ this.afterClose() } } } class T0XX{ init(){ this.openPop() } openPop(){ new D0XX().init({ afterClose(){ console.log(this) } }).close() } } new T0XX().init() //請問打印出結果是什麼?
最後,小Tip~就是之所以demo中可以使用鏈式呼叫是因為init方法中return出了this;這就跟jQuery中的鏈式呼叫有了異曲同工之妙;
如有不妥,歡迎指教!