首先這是之前提到過的匿名函式的第二個實參,乙個函式,用於傳遞給之前的factory的形參,而factory在存在window變數的情況下,將會執行factory(global),而這個global看第乙個實參表示式可以知道是this或者是window(當然,這裡會有差別,暫時不談),先撇開這,往下。
首先是之前忽略的嚴格模式,這裡必須要談了,嚴格模式和非嚴格模式有很大不同,比如我們在控制台下預設就是非嚴格模式,有如下例子,
function a()
b()//undefined
這裡僅選取需要的例子,也就是,嚴格模式下this將會不同,或者這樣說不夠貼切,首先,應該是這樣的:
我最開始碰見this是在cpp中,用於在類中省略乙個用於指向呼叫這個成員函式或正在被構造的物件的指標,也就是說,this指標是用於方便在執行時呼叫的上下文的(物件而不是類,所以是執行,上下文(context),這個理解可能有偏差,我的理解就是函式執行必然依靠乙個環境,多個大大小小的環境,就是上下文(context),如有不對,請指出,避免誤導),而js學習了cpp很多東西(用cpp寫成),也學習到了它的this,用於方便呼叫上下文的乙個東西,所以,this指向誰,首先要看誰呼叫函式。
在書中說,呼叫函式有四種方法(有不符合規定的情況不作討論):
初看時我是很疑惑的,函式呼叫不就是a()這樣嗎,其它幾種是什麼個搞法嘛,後面看過一些討論解析才有點頭緒,這裡所謂的函式呼叫的四種方法或許稱為函式執行的四種情況,也就是,誰在呼叫函式讓其執行。
首先使用函式呼叫表示式即可用作普通的函式呼叫也可以用作方法呼叫,也就是a(),而方法表示式與其區別就是多了乙個物件爸爸,o.m=f;o.m()
,這個樣,所以,上面**中有一系列如push=arr.push
這樣的形式,看起來也是搞了乙個函式別名,簡化操作,比如var a=} ;var k=a.c;k()
,但是就像這個例子一樣,k()不會有正確結果,而push(3,4),也不能使arr為[3,4],因為(push經常被舉例各種問題,這裡就上push的原始碼):
function arraypush()
this.length = n + m;
return this.length;
}
installfunctions($array.prototype, dont_enum,$array(
「tostring」, arraytostring,
「tolocalestring」, arraytolocalestring,
「join」, arrayjoin,
「pop」, arraypop,
「push」, arraypush,
)) 從**可以看出,push的操作首先要衡量一下引數的個數(%_argumentslength();),然後就簡單的this[i+n]這樣的為其賦值,所以經常被用來作爆記憶體的示例,因為push看起來就是這樣的–不能有效的控制其使用,但有這樣的乙個有意思**:
var obj={};
obj.m = push// push = arr.push
obj.m(3)
obj //
this.length =n+m
這樣對length為1很好理解, 但是,var n = tounit32(this.length);
,似乎表明了this.length—也就是undefined,被tounit32轉化為了0,首先,tounit32肯定是cpp函式了,先不去看這個裡面具體,用別的方式去看看:
obj.length = undefined
obj.m(5)
obj //
首先undefined不是關鍵字,而是乙個全域性變數,用於表示「空值」,類似的關鍵字null也表示空值,但是,從cpp來看,空指標並不是不存在,而是這個指標指向了乙個無法儲存值(或者說特別定義其無法儲存值),而undefined就是為了表示不存在而設立的,可能這一點從cpp角度來說有些疑惑,既然不存在,又為何又去需要確認其存在不存在?我個人認為很大程度上是歷史遺留問題(說不清,但從乙個動態語言角度來說,不存在是有道理的,不過我個人更傾向就是因為開始制定時的設計問題),
而將obj.length=nan
或者為null,都可以得到類似的結果,這一點看起來很奇怪,但實際上在我們自己寫**中,就會不經意間犯下類似的錯誤。
話題再回到函式呼叫,所謂作為函式呼叫或者方法呼叫,實際上就是乙個上下文問題,如果是存在乙個環境(比如在全域性中呼叫,或者某個函式中),那麼this指向全域性,注意,可以看下面的例子:
function a();
a();//window
b();//window
這種被稱作預設繫結,看著有些疑惑,為何b呼叫的a,卻不指向b,所以類似會有下面的疑惑:
var a = 3;
function d()
d()//3 ,如何得到函式裡面的5?
function c()
c()//5,看起了很奇怪
這個時候話題又轉到了作用域鏈,在函式定義時產生的作用域鏈用於儲存區域性變數,在函式執行時從裡往外查詢,所以直接用a就可以訪問到函式裡面的a,但是為何this.a不能這樣指向當前呼叫者?這裡給出我的一點想法(不準確,僅供提供乙個想法,歡迎討論:js中函式更像是cpp中的內聯函式,也就是僅僅是嵌入**而已,而這樣的嵌入,雖然會形成乙個新的作用域,但其所依賴的執行環境還是其最外層呼叫者,因為內部可以視作並無其它函式,而僅僅只是一行行**,所以this才有這樣詭異的表現,這在cpp中呼叫其它函式時的this表現其實是一致的,(比較混亂,因為我自己也不能理清裡面具體的東西)。
而作為方法呼叫,如:
var obj =
function a()
obj.m = a
obj.m()//3
這樣的方式稱作隱式繫結,也就是,在函式作為乙個物件的方法時,函式的this實際指向該物件,(預設其實類似,可以認為是this.c(),也就是實際是window物件呼叫了這個函式),作為對比,給個下面例子 :
var obj = }
obj.b.a=5
function c()
obj.b.m=c
obj.b.m()//5
這樣的結果看起來比較舒服,也從側面說明了,函式是物件的依附,有物件才能執行js中那些「無家可歸」的函式,而隱式繫結優先順序是比預設高的,事實上,預設繫結只在無法適用其它規則時才有效。
**var objectfunctionstring = fntostring.call( object );
這樣在某種程度上就是給函式找個家住,但又沒有成為這個家的成員,頂多算個旅客,所以這個時候this明確的被指定為執行obj。
關於顯式繫結用的地方很多,很多js的應用技巧都會用到這,在後面原始碼中有的地方將會具體舉例子
js中有new關鍵字,但是和cpp中不同,js中new實際只是呼叫函式的一種方式,而不是所謂的初始化,new的很大作用,就是改變this,這樣的繫結被特稱為new繫結,而new呼叫函式時,會有以下步驟:
1.建立或者說構建乙個全新的物件
2.這個新物件將會執行原型連線
3.這個新物件會繫結到這個函式呼叫的this
4.如果函式沒有返回值,那麼new會返回這個新物件
而new呼叫實際上會涉及到js中類與原型相關概念,在後面作出具體解釋。
函式呼叫的四種方式,對應了四種this的繫結,而四種繫結是有優先順序的,一般是顯式》隱式》預設,構造情況比較特殊,在這裡不作比較。
這裡需要注意,要注意返回值再進行這種鏈式操作
這個函式domeval,從名字可以看出,就是執行操作dom的函式,使其作用一次,然後消除影響,eval()這個函式用於執行動態**,比如eval("alert('test')"
,但一般不推薦使用這樣的操作,這樣會使得頁面結構凌亂。
之後原始碼,重頭戲:
var
version = "3.2.1",
// define a local copy of jquery
jquery = function( selector, context ) ,
jQuery原始碼學習筆記
整個jquery是乙個自呼叫的匿名函式 1 function global,factory 9return factory w 10 11 else 14 typeof window undefined window this,function window,noglobal 自呼叫函式大家都不陌生...
jquery原始碼學習筆記二 jQuery工廠
筆記一裡記錄,jquery的總體結構如下 function global,factory typeof window undefined window this,function window,noglobal 那麼這個生成jquery的工廠是咋樣的?醬紫的 function window,nogl...
jQuery原始碼分析系列
斷斷續續地看jquery原始碼,第一次萌生看jq原始碼的念頭,當時還是版本1.7.2,由於工作中沒有用到jq的機會,連 有幾種用法都還不知道,就開始啃原始碼,痛苦自然是少不了的,於是不久就放棄扔一邊了。等到工作中終於就機會用jq了 撒花 又萌生了啃jq原始碼的念頭,此時jq版本已經是2.0了。鑑於瀏...