JavaScript和Lua的類繼承

jopen 10年前發布 | 26K 次閱讀 JavaScript開發 JavaScript

javascript 本身雖是一門面向對象的編程語言, 但并沒有明確提供繼承方式.二十多年間,眾多高手提供很多模擬繼承的實現,

主要的有:對象冒充,call/apply,prototype,以及深復制等. 網上有很多此類教程,在這里就不再贅述這些實現.我所在的團隊正在做的項目,需要使用js和lua實現同一份API接口,已達到js和lua的無縫切換.所以,實現類的繼承方案至關重要. 接下來,就是具體實現過程, 如有不到之處,還望大家指正.

Lua ,是一門很優秀的動態語言,為嵌入而生,如果只是當成腳本使用的話,類的概念其實并不必要, 但是如果想要構成龐大規模的代碼量,這就一個亟待的問題,因為Lua 的操作符重載的支持, 使得這一過程得以實現.

javascript:

function Class(Super, init ){  //do  }

lua :   

function Class(Super , init ) --[[do]] end

*Super , 是新生成的類需要繼承的父類.

*init , 是新生成的類的構造函數. 

下面, 我們就來實現這個兩個Class函數.

  1.在js當中,調用new算符實際就是復制當前構造函數原型.因為Lua中并沒有new算符,所以應該將其屏蔽.

  2.在lua中想要實現方法的關聯,主要使用兩種方案, 一是復制,二是覆蓋元表__index索引,復制是一個很不錯的想法,或者說是一個極其通用的思想, 繼承的本質就是讓一個實例可以調用另外一個類實例的方法.如果是這樣的的話,復制是一個很完美的方案,簡單粗暴,簡單就是穩定,粗暴就是直接;穩定直接的方案往往是實現邏輯的最佳選擇,但是想要這個過程高效,那么就需要深厚的功力,我自認為還沒有達到這樣的水平, 所以,lua的實現機制還是選擇覆蓋元表__index索引實現.

  3. lua元表的__index索引,仔細想來,它的機制很像js的原型鏈, 也就是說讓lua模擬js的原型鏈還是比較容易的.而原型鏈的方式實現javascript的繼承也非常容易.

基于上述3點,下面貼出代碼:

lua

local setmetatable, pairs = setmetatable, pairs;

function Class(Super, init)
    local NEW = { fz = {} };---新的類定義, fz 就是實例方法所在的域 ,相當于js的prototype域.
    NEW.__initialize = function(self, ...) ---構造方法.
        local this = {}  
        for i, v in pairs(self) do    ---- 復制的 self 副本
            this[i] = v
        end 
        
        if init then
            init(this, ...);  ---執行初始化方法
        end
        
        return setmetatable(this, {     ---建立關聯.. 如果在NEW的實例域上沒有搜索到存在的域,那么
            __index = function(_, key)  ------就在NEW的fz下尋找. 
                return NEW.fz[key]
            end
        });
    end
    
    setmetatable(NEW.fz, {            ---建立關聯 .. 如果在NEW.fz上沒有找到存在的域,那么
        __index = function(_, key)    ------就在Super.fz 域上尋找, 如果找不到,就返回nil.
            return Super.fz and Super.fz[key] or nil;
        end
    });
    return setmetatable(NEW, {        ---設置元表的__call 域, 使得 NEW 這個hash表能夠被調用.
        __call = function(...)
            return (...).__initialize(...); --- 調用的時候直接轉到 初始化方法..
        end
    });
end

調用 : 

local M = Class({}, function(self , a , b ) ---  定義了類M , 繼承了table
    self.a = a
    self.b = b
end)
M.fz.geta = function(self)                  ---   定義實例方法 geta .
    return self.a;
end
local MM = Class(M , function(self, a , b)  ---  定義了類MM, 繼承了 M
    self.a = a
    self.b = b
end);
MM.fz.getb = function(self)                  --- 定義實例方法 getb.
    return self.b
end
local mm = MM( "AAA" , "BBB");              --- 獲得 MM 的實例 mm 
print(mm:geta())                            --- "AAA"
print(mm:getb())                            --- "BBB"

 

上述 代碼實現還是比較簡單的. 子類可以繼承父類  fz 下面的所有字段...

接下來就是js 的實現了..

因為 Lua 沒有關鍵字'new' , 所以js 的實現我將new 關鍵字做了屏蔽, 此處的參考了jQuery的實現,在此對john表示敬意.. 下面就是具體代碼:

function Class(Super, init) {
    var N = function () {           //創建一個空的函數N 做一個中間層.
    };                              
    N.prototype = Super.prototype;  // 將N的原型 指向 Super 的原型
    var New = function () {         //  要生成的類定義 NEW 
        return new New.fz.initialize(arguments);  
    };
    New.fz = New.prototype = new N();  //將 N的實例 關聯到 NEW 的原型上,并取一個別名 fz. 
    New.fz.initialize = function (M) {  //初始化方法.
        if (init) init.apply(this, M);
        return this;
    };
    New.fz.constructor = New;        // 將New.fz上的constructor域重定向到 NEW..
    New.fz.initialize.prototype = New.fz;  // 很高妙的處理,jQuery的實現.
    return New;
}

說明一下, 為什么會有一個 function  N :  其實是一個隔離考量. 前文提到的, 繼承 只是 prototype 關聯, 對其他域應該予以屏蔽.

所以給定一個  N , 這個 N 沒有任何實現,也沒掛載任何域, 只是將Super.prototype掛載到N.prototype上, 所以,new N() , 其實只是相當于一個指向Super.prototype的指針而已,

內存上幾乎沒有占用.. 至于隱藏 new 關鍵字,并沒有選擇工廠方法的實現, 而是直接使用jQuery 的實現方案..

調用:

var M = Class({}, function (a, b) {
    this.a = a;
    this.b = b;
});
M.fz.geta = function () {
    return this.a;
};
var MM = Class(M, function (a, b) {
    this.a = a;
    this.b = b;
});
MM.fz.getb = function () {
    return this.b
};
var mm = MM("AAA", "BBB");
print(mm.geta())
print(mm.getb())

依然是跟 lua 版本 一樣的調用方式......


來自:http://my.oschina.net/nanlou/blog/339255

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!