本文原創:liruifangjavascript
你是否被this困擾過? 求職時你是否在筆試或者面試的時候被問起過? 你是否在代碼中寫過self = this?java
this,究竟是何方神聖?git
this是一個很特別的關鍵字,被自動定義在 全部函數的做用域中 this 關鍵字是 JavaScript 中最複雜的機制之一github
科幻小說家亞瑟·查理斯·克拉克說過一句話:任何足夠先進的技術都和魔法無異。面試
在缺少清晰認識的狀況下,this 徹底就是一種魔法segmentfault
先看幾個例子~瀏覽器
正經解釋:bash
聽過不少道理 卻依然……app
不!融於意識、付諸實踐的道理,纔是你的道理。函數
1、調用位置
2、綁定規則
3、綁定優先級
4、凡事都有例外
this 的綁定,使用開發者工具獲得調用棧,而後找到棧中第二個元素,這就是真正的調用位置。
Bob.callPerson(John);
Bob called a person named John」
callPerson() 是 Bob 發起的,this 就指向 Bob。
複製代碼
- 答案:16
- 對象屬性引用鏈中只有最頂層或者說最後一層會影響調用位置。
- 無論有多少層,在判斷this的時候,咱們只關注最後一層。
複製代碼
- 雖然 bar 是 obj.foo 的一個引用,可是實際上,它引用的是 foo 函數自己
- bar() 實際上是一個不帶任何修飾的函數調用
- 重複強調:隱式綁定的形式 obj.fun()
複製代碼
經過call、apply、bind的方式,顯式地指定this所指向的對象。
- 答案:number is 2
- 執行fn的時候,至關於直接調用了foo方法(記住: obj.foo已經被賦值給fn了,隱式綁定也丟了),沒有指定this的值,對應的是默認綁定。
- 這顯然不是咱們想要的,怎麼辦?
複製代碼
調用fn顯式的強制綁定,硬綁定
咱們建立了函數 Hi(),並在它的內部手動調用 了 fn.call(obj),所以強制把 fn 的 this 綁定到了 obj。不管以後如何調用函數 Hi,它總會手動在 obj 上調用 fn。
複製代碼
思考: new 作了什麼?
1. 建立一個新對象
2. 將構造函數的做用域賦值給新對象,即this指向這個新對象
3. 執行構造函數中的代碼
4. 返回新對象
複製代碼
foo的this指向bar對象上
複製代碼
(一)默認綁定 var bar = foo()
嚴格模式下,綁定到undefined,不然綁定到 全局對象。
複製代碼
(二)隱式綁定 var bar = obj1.foo()
在某個上下文對象中調用,this 綁定的是那個上下文對象。
複製代碼
(三)顯式綁定 var bar = foo.call(obj2)
this綁定的是 指定的對象。
複製代碼
(四)new綁定 var bar = new foo()
this綁定的是新建立的對象。
複製代碼
new綁定 > 顯式綁定 > 隱式綁定 > 默認綁定
這樣就結束了嗎?
將null或undefined做爲this的綁定對象傳入call、apply或者是bind,這些值在調用時會被忽略,實際應用的是默認綁定規則。
- 答案:2
- foo() 內部建立的箭頭函數會捕獲調用時 foo() 的 this。因爲 foo() 的 this 綁定到 obj1, bar(引用箭頭函數)的 this 也會綁定到 obj1,箭頭函數的綁定沒法被修改。
複製代碼
(一)默認綁定 var bar = foo()
嚴格模式下,綁定到undefined,不然綁定到 全局對象。
複製代碼
(二)隱式綁定 var bar = obj1.foo()
在某個上下文對象中調用,this 綁定的是那個上下文對象。
複製代碼
(三)顯式綁定 var bar = foo.call(obj2)
this綁定的是 指定的對象。
複製代碼
(四)new綁定 var bar = new foo()
this綁定的是新建立的對象。
複製代碼
(五)箭頭函數
沒有本身的this,當前的詞法做用域覆蓋了 this 原本的值,this繼承於外層代碼庫中的this,且不可被修改。
複製代碼
歡迎再次來到this的魔法世界,讓咱們一塊兒升級打怪吧~
問題剖析,真相只有一個!
- 答案:
1 2
- 分析:
隱式綁定,this指向obj,num是1;
默認綁定:foo直接指向了foo的引用,和obj無關,是不帶任何修飾的函數調用 。
複製代碼
- 答案:hi,jadfe
複製代碼
- 分析:
setTimeout(fn,delay){ fn(); },至關因而將obj.foo賦值給了一個變量,最後執行了變量, foo是不帶任何修飾的函數調用這個時候,foo的this顯然和obj就沒有關係了。
複製代碼
- 答案:
Hello, Wiliam
Hello, Wiliam
Hello, Christina
- 分析:
① setTimeout的回調函數中,this使用的是默認綁定,非嚴格模式下,執行的是全局對象
② 上個例子剛分析了,跟setTimeout實現機制有關。
③ 第三條雖然也是在setTimeout的回調中,可是咱們能夠看出,這是執行的是person2.sayHi()使用的是隱式綁定,所以這是this指向的是person2。
複製代碼
- 答案:
2 2
- 分析:
箭頭函數,this繼承於外層的this
默認綁定:foo是不帶任何修飾的函數調用
複製代碼
- 答案:
2
- 分析:
箭頭函數經常使用於回調函數中,this繼承於外層foo的this,foo中的this顯示綁定到obj上,所以至關於obj.a = a4-5
複製代碼
- 答案:
Obj對象
Obj對象
Window對象
Window對象
Window對象
- 分析:
① obj.hi(); 隱式綁定,this綁定在obj上,輸出obj。
② hi(); 執行箭頭函數,繼承外層做用域的this。
③ sayHi(); 隱式綁定丟失的狀況,this執行的是默認綁定,指向全局對象window。
④ fun1(); 執行的是箭頭函數,this是繼承於外層代碼庫的this。外層代碼庫咱們剛剛分析了,this指向的是window,所以這兒的輸出結果是window。
⑤ obj.say(); 執行的是箭頭函數,當前的代碼塊obj中是不存在this的,只能往上找,就找到了全局的this,指向的是window。
複製代碼
- 答案:
0 NaN
- 分析:
看調用位置,顯示綁定,
無心中建立了一個全局變量 count
這個count值是什麼?
有些地方稱值爲NaN是錯誤的,值爲undefined,++運算符,類型轉換NaN
複製代碼
- 答案:
5
- 分析:
將null或undefined做爲this的綁定對象傳入call、apply或者是bind,
這些值在調用時會被忽略,實際應用的是默認綁定規則
複製代碼
1. 函數是不是new綁定,若是是,那麼this綁定的是新建立的對象。
2. 函數是否經過call,apply,bind調用顯式綁定,若是是,那麼this綁定的就是指定的對象。
3. 函數是否在某個上下文對象中調用(隱式綁定),通常是obj.foo(),若是是的話,this綁定的是那個上下文對象[注意隱式丟失的狀況]。
4. 若是以上都不是,那麼使用默認綁定。在嚴格模式下,則綁定到undefined,不然綁定到全局對象。
5. 若是把null或者undefined做爲this的綁定對象傳入call、apply或者bind,這些值在調用時會被忽略,實際應用的是默認綁定規則。
6. 若是是箭頭函數,箭頭函數的this繼承的是外層代碼塊的this。
複製代碼
若是你已經很是清楚的知道怎麼判斷this的指向,那就試試這道題吧~
答案:
10
9
3
27
20
複製代碼