最近在使用kendo ui的時候遇到一些問題,有一個需求是希望在打開LOV組件的時候不執(zhí)行查詢操作。但是在kendo官網(wǎng)上并沒有看到任何有關(guān)LOV的文檔或者API,于是猜想LOV可能是公司基于kendo ui封裝的一個組件。經(jīng)過查看源碼發(fā)現(xiàn)確實如此,所有代碼都在kendo.all.js 這個文件中,差不多7W行的代碼,能找到LOV組件的實現(xiàn)代碼著實是依賴于IDEA這個強大的工具。問題最終得到解決,稍微修改一下部分源代碼,可以滿足這個需求,而且發(fā)現(xiàn)這個LOV組件在設(shè)計之初確實沒有提供一個參數(shù)來選擇是否在打開的時候查詢,這其實算是一個比較通用的需求,應(yīng)該算是設(shè)計上的一點缺陷吧。沒有見過LOV的童鞋這里可以給你們展示一下,它是長這樣的:
初始化的時候,是長這樣的,和一個普通的 輸入框 很像,箭頭標注的地方就是LOV
當(dāng)我們點擊那個小小的搜索按鈕時,會彈出一個窗口,窗口中的內(nèi)容更像是一個Grid,如圖:
當(dāng)我們雙擊grid中的一行記錄的時,會把值重新帶回到界面的那個輸入框中。
這里展示了LOV組件的基本使用,在實際開發(fā)中,配置這樣的一個LOV只需要短短的幾分鐘,可以節(jié)約大量的時間成本。當(dāng)然還有很多細節(jié),這里不過多介紹,因為這是需要前端和后臺一起支持才能使用的。
需求可以實現(xiàn)了,這給了我極大的信心,畢竟從這么多代碼里找出一部分然后修改一部分也很有意思。于是在修改之后又去看了一部分kendo ui的源碼,感覺還好,有很多地方并不清楚,但是大概能知道什么意思,我目前要的就是這個效果,也不指望能馬上明白每一行代碼的用意,這需要特別特別扎實的基礎(chǔ)功,我目前是做不到的。效果還是有一些的,很多之前不知道的API在源碼里面都可以看到,這至少對我之后在使用kendo時是有幫助的,另一個好處就是讓我明確了目前這一階段在前端這一塊的學(xué)習(xí)方向:JQuery。kendo 中到處都是JQuery,因為之前簡單的看過一點點JQuery源碼,那時候根本一點都看不懂,但還是有一點點印象。雖然我菜,但是我有一顆學(xué)習(xí)的心啊,當(dāng)時就覺得JQuery很重要,我想看它的目的也不是想要完全理解這個庫,而是希望通過學(xué)習(xí)它來幫助自己對JS一些特性的理解,在學(xué)習(xí)的過程中會遇到各種各樣的問題,然后就會有針對性的去找文檔、查資料,我覺得這種學(xué)習(xí)方式很好。
閉包與IIFE
什么是閉包?我覺得我肯定是說不清楚的,或者我根本就沒理解吧,因為在很多情況下,我并不知道那到底屬不屬于閉包,JS太靈活了。網(wǎng)上找了一點說明,可能時間久了就有感覺了吧。
閉包就是一個函數(shù)引用另外一個函數(shù)的變量,因為變量被引用著所以不會被回收,因此可以用來封裝一個私有變量。
function a(){
var n = 0;
function inc(){
n++;
console.log(n);
}
return inc;
}
var c = a();
c(); //控制臺輸出1
c(); //控制臺輸出2
有權(quán)訪問另一個函數(shù)作用域內(nèi)變量的函數(shù)都是閉包。
- 一個陷阱
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
}
var funcs = createFunctions();
for (var i=0; i < funcs.length; i++){
console.log(funcs[i]());
}
輸出結(jié)果不是 0-9, 而是10 個 10 !
這里面這句話是關(guān)鍵 “閉包就是一個函數(shù)引用另外一個函數(shù)的變量,因為變量被引用著所以不會被回收”。
在這段JS中,for語句塊并沒有自己的作用域,也就是說 i 的作用域是屬于 createFunctions 函數(shù)的。這里的 匿名函數(shù)訪問了 createFunctions 函數(shù)里面的 i 變量,所以形成了一個閉包。
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
在執(zhí)行完這段循環(huán)之后,i 的值變成了 10 ,而在 i 變成 10 之前, 函數(shù)并沒有調(diào)用。函數(shù)帶()才是執(zhí)行函數(shù)!
所以在執(zhí)行以下語句的時候,i 的值已經(jīng)是 10 了。
for (var i=0; i < funcs.length; i++){
console.log(funcs[i]());
}
IIFE(Immediately-Invoked Function Expression),即 立即調(diào)用的函數(shù)表達。
比如,下面就是一個 立即執(zhí)行函數(shù)
;(function (參數(shù)) {
// 模塊代碼
// return something;
})(參數(shù)));
它的結(jié)構(gòu)可以看作是以下三部分組成:;、匿名函數(shù)、()
最后的一對括號是對匿名函數(shù)的調(diào)用,因此必不可少。而前面的一對圍繞著函數(shù)表達式的一對括號并不是必需的,但它可以用來給開發(fā)人員一個指示 – 這是一個 IIFE。也有一些開發(fā)者在函數(shù)表達式前面加上一個驚嘆號(!)或分號(;),而不是用括號包起來:
!function (參數(shù)) {
// 代碼
// return something
}(參數(shù));
還可以用一個大括號包起來
(function (參數(shù)) {
// 代碼
// return something
}(參數(shù)));
在有些人的代碼中,將 undefined 作為上面代碼中的一個參數(shù),他們那樣做是因為 undefined 并不是 JavaScript 的保留字,用戶也可以定義它,這樣,當(dāng)判斷某個值是否是 undefined 的時候,判斷可能會是錯誤的。將 undefined 作為一個參數(shù)傳入,是希望代碼能按預(yù)期那樣運行。
(function (參數(shù)1, undefined ) {
// 代碼
// return something
}(參數(shù)1));
如上,當(dāng)傳入入第二個參數(shù)的時候, undefined 就是真正的undefined。
我為什么要一開始的時候就寫這個?因為JQuery一開始就是這么干的啊,不光是JQuery,大部分框架一開始都是這么干的。作為一個技術(shù),我覺得如果我想理解JQuery,我一開始就想知道這開頭代碼是什么意思,要不然心里不舒服。So,I have no choice.
了解了這個,下面可以開始看看源碼了,版本 3.3.1。
( function( global, factory ) {
"use strict";
if ( typeof module === "object" && typeof module.exports === "object" ) {
// For CommonJS and CommonJS-like environments where a proper `window`
// is present, execute the factory and get jQuery.
// For environments that do not have a `window` with a `document`
// (such as Node.js), expose a factory as module.exports.
// This accentuates the need for the creation of a real `window`.
// e.g. var jQuery = require("jquery")(window);
// See ticket #14549 for more info.
module.exports = global.document ?
factory( global, true ) :
function( w ) {
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
return factory( w );
};
} else {
factory( global );
}
// Pass this if window is not defined yet
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
//代碼
});
傳入兩個參數(shù),第二個參數(shù)是一個 函數(shù),JQuery的主要代碼,就是在這個函數(shù)中實現(xiàn)。其實這里面涉及到另一個知識點,JS模塊。有關(guān)于JS模塊的內(nèi)容,在文章的開頭處已經(jīng)給了相關(guān)鏈接。
if ( typeof module === "object" && typeof module.exports === "object" ) {
}
這只是對JS執(zhí)行環(huán)境的一個檢測,判斷當(dāng)前的JS執(zhí)行環(huán)境是在瀏覽器,還是支持 CommonJS Modules 規(guī)范。與 CommonJS Modules 對應(yīng)的,還有 AMD,還有就是ES6 標準的模塊化解決方案。