在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ C/ John Resiq 的繼承寫法解析
cocos2d-x for js 中的繼承
JS 與 C++ 的交互 1——JS 代碼調(diào)用 C++ 代碼
迎接腳本時代的到來
解決在 vs 中修改 js 源文件無效
JS 腳本語言的優(yōu)勢與一些問題
注冊函數(shù)
回調(diào)函數(shù) 2
cxx-generator JS 綁定工具
使用 cocos2d-console 工具轉(zhuǎn)換腳本為字節(jié)碼
hybrid 開發(fā)模式
JS 與 C++ 的交互 2——JS 與 C++ 的“函數(shù)重載”問題
回調(diào)函數(shù)1——按鍵回調(diào)
Google 的繼承寫法解析
John Resiq 的繼承寫法解析
JS 與 C++ 的交互 3——C++ 和 JS 類型轉(zhuǎn)換
傀儡構(gòu)造函數(shù)

John Resiq 的繼承寫法解析

今天,我們來看看 John Resiq 的繼承寫法 Simple JavaScript Inheritance。之前已經(jīng)有很多同行分析過了。這個寫法 在cocos2d-x for js 中也被使用,并作了少許改動。我嘗試著做一些展開描述。 先貼源碼:

cc.Class = function(){};  
cc.Class.extend = function (prop) { 
    var _super = this.prototype;  

    // Instantiate a base class (but only create the instance, 
    // don't run the init constructor) 
    initializing = true; 
    var prototype = new this(); 
    initializing = false; 
    fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; 

    // Copy the properties over onto the new prototype 
    for (var name in prop) { 
        // Check if we're overwriting an existing function 
        prototype[name] = typeof prop[name] == "function" && 
            typeof _super[name] == "function" && fnTest.test(prop[name]) ? 
            (function (name, fn) { 
                return function () { 
                    var tmp = this._super; 

                    // Add a new ._super() method that is the same method 
                    // but on the super-class 
                    this._super = _super[name]; 

                    // The method only need to be bound temporarily, so we 
                    // remove it when we're done executing 
                    var ret = fn.apply(this, arguments); 
                    this._super = tmp; 

                    return ret; 
                }; 
            })(name, prop[name]) : 
            prop[name]; 
    } 

    // The dummy class constructor 
    function Class() { 
        // All construction is actually done in the init method 
        if (!initializing && this.ctor) 
            this.ctor.apply(this, arguments); 
    } 

    // Populate our constructed prototype object 
    Class.prototype = prototype; 

    // Enforce the constructor to be what we expect 
    Class.prototype.constructor = Class; 

    // And make this class extendable 
    Class.extend = arguments.callee; 

    return Class; 
}; 
cc.Class = function(){};  

做了一個全局構(gòu)造函數(shù) Class,這個不需要什么解釋。

cc.Class.extend = function (prop) {  

prop 是一個對象字面量,這個對象包含了子類所需要的全部成員變量和成員方法。 extend 函數(shù)就在內(nèi)部遍歷這個字面量的屬性,然后將這些屬性綁定到一個“新的構(gòu)造函數(shù)”(也就是子類的構(gòu)造函數(shù))的原型上。

var _super = this.prototype; 

注意,js 里面的這個 this 的類型是在調(diào)用時指定的,那么這個 this 實際上是父類構(gòu)造函數(shù)對象。比如你寫了一個 MyNode 繼承自 cc.Node。相應(yīng)代碼是:

var MyNode = cc.Node.extend({ 
    var _super = this.prototype;
... 
}); 

那么這個 this 就是父類 cc.Node。

initializing = true; 
var prototype = new this(); 
initializing = false; 

生成父類的對象,用于給子類綁定原型鏈。但要注意,因為這個時候,什么實參都沒有,并不應(yīng)該給父類對象中的屬性進行初始化(構(gòu)造器參數(shù)神馬的木有怎么初始化啊喵,這玩意實際是 JS 語言設(shè)計上的失誤造成的)。所以用一個變量做標記,防止在這個時候進行初始化。相關(guān)代碼在后面就會看到。

fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;  

這玩意看起來很亂,這是一個正則對象,右邊是一個?表達式,中間添加了一些正則代碼。這個對象的作用是,檢測子類函數(shù)中是否有調(diào)用父類的同名方法“_super()”(這種調(diào)用父類方式是由 John Resiq 約定的)。但這種檢測需要 JS 解釋器支持把一個函數(shù)轉(zhuǎn)換為字符串的功能,有些解釋器是不支持的。所以我們先做一個檢測,自己造了一個函數(shù),里面有 xyz,然后用正則的 test 函數(shù)在里面搜索 xyz。如果返回 true,表示支持函數(shù)轉(zhuǎn)字符串,那么就直接返回/\b_super\b/否則返回/.*/

 for (var name in prop) {  
        prototype[name] = typeof prop[name] == "function" &&  
            typeof _super[name] == "function" && fnTest.test(prop[name]) ?  
            (function (name, fn) {  
                return function () {  
                    var tmp = this._super;  
                    this._super = _super[name];   
                    var ret = fn.apply(this, arguments);   
                    this._super = tmp;
                    return ret;  
                };  
            })(name, prop[name]) :  
            prop[name];  
}  

現(xiàn)在重頭戲來了,在這個地方我們要把傳進來的那個字面量 prop 的屬性全都綁定到原型上。這地方又他喵的是一個?表達式,JR 實在太喜歡用這玩意了。首先,forin 把屬性拿出來。然后,因為我們添加的功能是“實現(xiàn)像 c++ 那樣通過子類來調(diào)用父類的同名函數(shù)”,那么需要檢測父類和子類中是否都有這兩個同名函數(shù)。用的是這段代碼:

typeof prop[name] == "function" && typeof _super[name] == "function" 

然后,我們還要檢測,子類函數(shù)中是否真的使用了_super 去調(diào)用了同名的父類函數(shù)。這個時候,之前的正則對象 fnTest 出場。繼續(xù)之前的話題,如果解釋器支持函數(shù)轉(zhuǎn)字符串,那么 fnTest.test(prop[name]) 可以正常檢測,邏輯正常進行;如果不支持,那么 fnTest.test(prop[name]) 始終返回 true。
這玩意什么用處,這是一個優(yōu)化,如果子類函數(shù)真的調(diào)父類函數(shù)了,就做一個特殊的綁定操作(這個操作我們后面馬上講),如果子類函數(shù)沒有調(diào)父類函數(shù),那么就正常綁定。如果沒法判斷是否調(diào)用了(解釋器不支持函數(shù)轉(zhuǎn)字符串),直接按照調(diào)用了那種情況來處理。雖然損失一些性能,但是可以保證不出問題。

(function (name, fn) {   
    return function () {   
        var tmp = this._super;   
        this._super = _super[name];    
        var ret = fn.apply(this, arguments);    
        this._super = tmp; 
        return ret;   
    };   
})(name, prop[name]) 

繼續(xù),上面的就是我們說的那個特殊的綁定操作。在這里,我們做了一個閉包,這里面的 this 是子類對象,跟之前的那個 this 不一樣哦。我們利用閉包的特性,保存了一個 _super,這個 _super 被綁定了父類的同名函數(shù)_super[name]。然后我們使用 fn.apply(this, arguments)調(diào)用子類函數(shù),并保存返回值。因為這是一個閉包,所以根據(jù)語法,我們可以在 fn的實現(xiàn)中調(diào)用 _super 函數(shù)。

function Class() {  
   if (!initializing && this.ctor)  
        this.ctor.apply(this, arguments);  
}  

Class.prototype = prototype;   
Class.prototype.constructor = Class;   
Class.extend = arguments.callee; 

生成一個 Class 構(gòu)造函數(shù),這個構(gòu)造函數(shù)作為這個大匿名函數(shù)的返回值使用。然后里面就是之前說的,初始化保護,防止在綁定原型鏈的時候初始化。注意后面那個玩意 ctor,在 cocos2d-x for js 中,真正的初始化是二段構(gòu)造的那個 init,而不是 ctor。在 cocos2d-x for js 的實現(xiàn)中 ctor 里面會調(diào)用一個函數(shù) cc.associateWithNative(this, 父類),這個函數(shù)負責后臺生成一個 c++ 對象,然后把 c++ 對象和 js 對象綁定到一起。

剩下的是例行公事:綁定子類的原型,修正子類的構(gòu)造器指向它自己,給子類添加一個同樣的 extend 方法。 最后把這個完成的構(gòu)造函數(shù)返回出來。