博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript和Lua的类继承
阅读量:7063 次
发布时间:2019-06-28

本文共 3795 字,大约阅读时间需要 12 分钟。

  hot3.png

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 = bend)M.fz.geta = function(self)                  ---   定义实例方法 geta .    return self.a;endlocal MM = Class(M , function(self, a , b)  ---  定义了类MM, 继承了 M    self.a = a    self.b = bend);MM.fz.getb = function(self)                  --- 定义实例方法 getb.    return self.bendlocal 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 版本 一样的调用方式......

转载于:https://my.oschina.net/nanlou/blog/339255

你可能感兴趣的文章
Oracle的常见错误及解决办法
查看>>
一花一世界(转)
查看>>
winform 控件部分
查看>>
BZOJ1066 蜥蜴
查看>>
从substring()方法看android的容错机制有待改进.
查看>>
迅雷诚聘高级UI设计师
查看>>
ifconfig: command not found
查看>>
数据库优化-水平拆分 垂直拆分
查看>>
aliyun默认分区挂载表
查看>>
(三)控制浏览器操作
查看>>
进程控制编程
查看>>
Postgresql 数据库,如何进行数据备份以及导入到另外的数据库
查看>>
python之闭包、装饰器
查看>>
实现单例模式的9个方法
查看>>
实现上一篇,下一篇的效果
查看>>
ROS中的通信机制
查看>>
查询表达式和LINQ to Objects
查看>>
Jmeter(七)关联之JSON提取器
查看>>
2017-2018-2 《网络攻防》第四周作业
查看>>
Java学习之Iterator(迭代器)的一般用法 (转)
查看>>