對《javascript 雜談之哪種寫法你更喜歡?》最后一種“匿名函數法”的解釋


前兩天看了篇不錯的關於javascript寫法的文章。在評論里,不少人表示看不懂最后一種方法,作者也沒詳細說明,於是我順勢解說,算是沾點人氣。

代碼如上圖,整體結構模仿jQuery,代碼不長,知識點較多,信息量很大,我們分兩部分,逐行解釋。

第一部分

第一部分中,我們把extend相關的方法抽離,剩余代碼如下:

(function () {
        var yQuery = (function () {
            var yQuery = function () {
                return yQuery.fn.init();
            };

            yQuery.fn = yQuery.prototype = {
                init: function () {
                    return this;
                }
            };
            return yQuery;
        })();
        window.yQuery = window.$ = yQuery();
    })();

知識點1:無引用的匿名函數調用

(function() {
    })();

這種寫法作用是聲明並執行一個方法,等同於:

function Test() {
    }
    Test();

知識點2:屬性變量無需聲明

var obj = new Object();
 obj.name = "abc";

obj並沒有name屬性,但無需聲明就可以使用,初始值為undefined。上例中yQuery.fn 就沒有聲明。

知識點3:{}二義性,相當於創建一個對象。

var obj = new Object();
var obj = { };

在js中,{}除了可作為復合語句邊界以外,還有創建一個空對象的作用,因此上面這兩句相同。而在例子中用到的情況如下:

        {
            init: function () {
                return this;
            }
        };

這段代碼猛一看像方法,實質是一個包含了init方法的對象,而方法中的this指向這個對象本身。

知識點4:連等表達式

var a = b = 1;

這個比較好理解,相當於對他們分別賦同一個值。在上例中,yQuery.fn就用到了這個寫法。

知識點5:原型繼承prototype

yQuery.fn = yQuery.prototype = {
                init: function () {
                    return this;
                }
            };

例子中,通過連等分別對yQuery.fn和yQuery.prototype賦值給了同一個對象。而fn的作用只是一個別名,只為書寫方便,重點是給prototype賦值,為什么要給它賦值?在本例中無法解釋。

在jQuery中,init方法會返回不同對象,而本例中永遠返回同一個對象,因此這里prototype沒有多大意義。至於jQuery為什么要用prototype,算是題外話了,有興趣的可點這里

第一部分代碼含義

這段代碼第二行yQuery和第三行的yQuery是兩個變量,因名字相同,所有很有迷惑性。整段代碼意思就是:yQuery.prototype指向了一個包含init方法的對象,prototype有個別名fn,可通過yQuery.fn.init()返回這個對象,最后把這個對象賦值給window.$和window.yQuery屬性。

第二部分

看完了第一部分,第二部分就相對簡單了,代碼如下:

yQuery.extend = yQuery.fn.extend = function () {
                var options, name, src, copy,
                    target = arguments[0] || {},
                    i = 1,
                    length = arguments.length;
                if (length === i) {
                    target = this;
                    --i;
                }

                for (; i < length; i++) {
                    if ((options = arguments[i]) != null) {
                        for (name in options) {
                            src = target[name];
                            copy = options[name];

                            if (src === copy) {
                                continue;
                            }
                            if (copy!==undefined) {
                                target[name] = copy;
                            }
                        }
                    }
                }
                return target;
            };

知識點1:函數中的arguments變量

函數內部會自帶一個arguments變量,該變量記錄傳入的參數,從左至右分別是arguments[0],arguments[1]等,js奇怪的地方在於,你聲明了一個無參函數,在調用的時候依然可以傳入參數,比如:

function NoArg() {
        console.log(arguments[0]);
        console.log(arguments[1]);
        console.log(arguments[2]);
    }
    NoArg(1, 2, "a");

該例NoArg調用時,會正常顯示傳入參數。

知識點2:結果類型不確定的邏輯運算

js中,所有類型都可以進行邏輯判斷(true或false),js會將值轉化為布爾值,但並不改變原值。如:

var str = "a";
    if(str) {
    }

此處的str為true,該特性與邏輯運算符”||”和”&&”結合形成了js一大特點,代碼如下:

var str = "a";
var num = 1;
var x = str || num; //x="a"
var y = str && num; //y=1;

js支持“邏輯短路”,所謂邏輯短路是指:

  1. 在”||” 運算中,第一個條件符合就結束判斷。
  2. 在”&&”運算中,第一個條件不符合就結束判斷。

因此,”str || num”的str為true,則結束判斷,返回str。”str&&num”的str為true,則繼續判斷num,num為true,則返回num。在本文案例中,有幾個地方用到了這個特性:

target = arguments[0] || {}

容易看出,如果arguments[0]有值則返回該值,不然就通過{}返回一個空的對象。還有一處在圖片中有,我文中沒有打出來的代碼:

$.ui = $.ui || { };

知識點3:數組方式訪問對象屬性

var obj = new Object();
obj.name = "a";
obj["name"] = "a";

最后兩行代碼等效。

第二部分代碼含義

這部分代碼可簡單描述為:定義一個方法,將參數1之外的所有參數的屬性成員賦值給參數1。我把循環部分修改一下,能更容易看懂,代碼如下:

for (; i < length; i++) {
        if ((options = arguments[i]) != null) {
            for (var name in options) {
                if (options[name] !== undefined) {
                    target[name] = options[name];
                }
            }
        }
    }

結語

js中有不少語法和運算符存在二義性,這導致js代碼顯的混亂難懂,所以不少人罵js是一個2B的語言,我覺得也不無道理。不過隨着js的應用范圍越來越廣泛,終究避不開它,因此罵歸罵,學還是要學的。

我是看了周愛民老師的《JavaScript語言精髓與編程實踐(第2版)》后才算對js真正入門,飲水思源,推薦此書。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM