摘要:貼一句書中的原文就是說在代碼中很簡單,沒有任何修飾的調用,就可以理解為全局的作用域對象。這種鏈式賦值,指向問題在中叫做。在這種傳一個參數作為對象的功能方面,與是等價的。看了以上文章對于解決面試題應該會有不小的幫助。
書讀到"this & object prototype"這一卷。 章節到了“this All Makes Sense Now!”
書里面開篇就提到,this并不復雜,只不過被很多程序員加了自己的臆想以訛傳訛,說到底,還是基礎知識不熟悉。
的確,看過很多技術文章,分析this都有那種管中窺豹的感覺就是著重在舉例,論述這個現象,而不求甚解。
閑言少敘,開始總結。
首先說一個重要的技術名詞,call-site,我們平時在debug的時候,可能會接觸到callstack這個詞,感覺上其實有那么一點類似。
我理解:
call-stack:是一連串的方法執行的鏈式結果
call-site:只是上一個調用當前方法上下文環境,可以理解為context。
比如下面這個片段:
function callfirst(){ // call-stack:callfirst // call-site:全局 callsecond(); } function callsecond(){ // call-stack:callfirst -> callsecond // call-site:callfirst } callfirst();
為什么說到這個call-site,確定this對象其實就是找到call-site的過程。
說到這里,還要再提一個細節,js中的this,不是面向對象中傳統的概念,這個this不是放在function中就是這個function的context,也不是任何場合都代表了整個js運行環境中的context,這個this,你就可以理解為是剛才提到的call-site,必須是有依據的context。
下面就總結一下找到call-site的方法,也就是如何正確找到并使用this。(規則我就直接使用原文的副標題)
1.Default Binding:看看如下代碼片段function foo() { console.log( this.a ); } var a = 2; foo();
這里出現this的地方,是foo方法里,我們先確定call-site,顯而易見,foo方法的call-site就是最后一行foo,隸屬于全局對象,那么這個this就呼之欲出了,這個this就代表這個代碼的作用域,而this.a訪問的也就是var a = 2;這條語句賦值的屬性,所以控制臺會打印出一個2。
貼一句書中的原文:
“called with a plain, un-decorated function reference. ”
就是說在代碼中很簡單,沒有任何修飾的調用,this就可以理解為全局的作用域對象。
但是這種規則,不適用于strict mode環境下的js代碼,如果用在strict mode中,以上代碼需要改寫成為
function foo() { console.log( this.a ); } var a = 2; (function(){ "use strict"; foo(); // 2 })();2.Implicit Binding:還是看代碼
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; obj.foo();
這種直譯為隱式綁定的方法,確定call-site的方法就是看是由誰調用的方法,在上面這個例子中,再直白以及明顯不過了,obj中有一個foo屬性,綁定的foo方法,那么此時foo方法中的call-site就是obj,obj中有一個屬性是a,所以代碼會輸出2
變形:
function foo() { console.log( this.a ); } var obj2 = { a: 42, foo: foo }; var obj1 = { a: 2, obj2: obj2 }; obj1.obj2.foo(); // 42
如果遇到這種鏈式的風格,就本著就近原則,離foo方法最近的obj2就是foo的call-site,方法中this.a的值就是obj2中a的值。
在Implicit Binding的情況下會有一種叫Implicitly Lost的情況發生,簡單直白點說就是剛才那種鏈式調用的方式,被隱藏在了各種其他的情況之下,舉例來說明。
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; var bar = obj.foo; var a = "oops, global"; bar();
上面這種情況將obj.foo賦值給了bar, 按照慣性思維,看到obj.foo第一反應,我覺得this應該等價于obj,然而事實卻哐哐打臉,
上面代碼的foo的call-site是bar,雖然鏈式復制了一大堆給了bar,但實際上,bar在這個時點是等價于foo的,所以這個方法的call-site就是bar,那么this.a的值就是全局屬性的a,與obj就不相干了。
與上面情況相同的還有如下幾種變種情況:
function foo() { console.log( this.a ); } function doFoo(fn) { fn(); } var obj = { a: 2, foo: foo }; var a = "oops, global"; doFoo( obj.foo );
刨除一切感官上的理解,最終調起foo方法的是fn()這句話,fn的值雖然是由obj.foo傳過來的,但其實這種情況與上面說到的方式完全是等價的
解析一下,fn()就是foo的call-site,而根據第一個default binding原則,fn前面是干凈沒有任何修飾符的,所以foo中的this代表的就是全局對象。
這里需要強調的就是,鏈式方法無論是賦值還是作為方法的參數,不能被長長的語句迷惑雙眼,照準call-site是理順思路的一切法門。
這種鏈式賦值,this指向問題在js中叫做fall back to default binding。
3.Explicit Binding說到這個顯示綁定,就得提到兩個方法,一個叫做call,另一個叫apply,在現在這個時點,我們暫且理解幾個點,這兩個方法,是所有function對象都可以調用的內建方法(涉及到prototype),他們的第一個參數,我們就可以理解為this對象,這是一種強制把this注入到方法中的一種手段。舉個例子
function foo() { console.log( this.a ); } var obj = { a: 2 }; foo.call( obj );
還是熟悉的味道,但是我們卻換了配方,我們不直接調用foo方法,而是使用foo中的call方法,把obj傳到call中作為foo中的this對象,控制臺會為我們輸出一個2,call可以換成apply。
foo.apply(obj);
在這種傳一個參數作為this對象的功能方面,call與apply是等價的。
4 new Binding這個恐怕也是很多使用js的朋友們最容易混淆的地方,new在js中生成的只是一個function,new過是在一個function前面搶了一個new單詞,而這樣表示會讓function有一些新的變化
大體上有4點:
產生一個新的function對象
這個與原型鏈有關,暫且不說
new出來的function對象調用的方法是使用的this,就是它本身
除對象本身改變自己本身以外,每次new出來的對象都是全新的對象(這話我再潤色一下)
上例子:
function foo(a) { this.a = a; } var bar = new foo( 2 ); console.log( bar.a );
這個比之之前的復雜情況就太淺顯了,望文生義即可。
看了以上文章對于解決this面試題應該會有不小的幫助。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82805.html
摘要:設計模式與開發實踐讀書筆記。發布訂閱模式又叫觀察者模式,它定義了對象之間的一種一對多的依賴關系。附設計模式之發布訂閱模式觀察者模式數據結構和算法系列棧隊列優先隊列循環隊列設計模式系列設計模式之策略模式 《JavaScript設計模式與開發實踐》讀書筆記。 發布-訂閱模式又叫觀察者模式,它定義了對象之間的一種一對多的依賴關系。當一個對象的狀態發生改變時,所有依賴它的對象都將得到通知。 例...
摘要:設計模式與開發實踐讀書筆記。看此文章前,建議先看設計模式之發布訂閱模式觀察者模式在中,已經介紹了什么是發布訂閱模式,同時,也實現了發布訂閱模式。 《JavaScript設計模式與開發實踐》讀書筆記。 看此文章前,建議先看JavaScript設計模式之發布-訂閱模式(觀察者模式)-Part1 在Part1中,已經介紹了什么是發布-訂閱模式,同時,也實現了發布-訂閱模式。但是,就Part1...
閱讀 2761·2021-09-24 10:34
閱讀 1862·2021-09-22 10:02
閱讀 2253·2021-09-09 09:33
閱讀 1459·2021-08-13 15:02
閱讀 3271·2020-12-03 17:10
閱讀 1180·2019-08-30 15:44
閱讀 2144·2019-08-30 12:58
閱讀 3229·2019-08-26 13:40