在设计实现一种Java、Objective-C与JavaScript混合编程的编程风格JSAppSugar时,须要 JavaScript 语言支持类导向的编程风格,然而JavaScript自己是原型导向(Prototype-based)的,所以在JavaScript中也有不少种实现类继承的方式。这里介绍一下JSAppSugar中实现类继承和super方法调用的实现方式。javascript
查看源码:https://github.com/JSAppSugar/JSA4JS/blob/master/src/JSAppSugar.jsjava
该JS文件设计用于JSA4Cocoa和JSA4Java中,以实现JavaScript与Java、Objective-C混合编程,也可单独使用在普通JavaScript程序中实现类继承和父类方法调用。git
JSAppSugar编程风格定义一个基础类、子类,以及在子类中调用父类方法。github
$class("my.sample.Person",{ name : "Unknown", $init : function(name){ if(name) this.name = name; }, eat : function(food){ return this.name + " is eating "+food; } }); $class("my.sample.Programmer",{ $extends : "my.sample.Person", title : "Programmer", $init : function(title,name){ $super(name); if(title){ this.title = title; } } eat : function(food){ return this.title + " " + $super.eat(food); } });
其中 $init 表示为构造器方法编程
调用:闭包
var bob = new my.sample.Person("Bob"); var bobDoing = bob.eat("Salad"); //函数将返回字符串 Bob is eating Salad var bill = new my.sample.Programmer("CTO","Bill"); var billDoing = bill.eat("Sausage"); //函数将返回字符串 CTO Bill is eating Sausage
JSAppSugar实现类继承的方式采用了原型链方式:app
initializing = true;//闭包属性,用于在建立原型链父类对象时避免调用父类的构造器方法 JSAClass.prototype = new SuperClass();//构造原型链 initializing = false; JSAClass.prototype.constructor = JSAClass;//不是构造原型链继承的必须,设置目的是为了经过类对象查找到类原型
构造器方法的实现(这里只列出了关键代码):函数
JSAClass = function(){ if(!initializing && this.$init){//initializing为判断是否在构造原型链,若是是则忽略执行构造器方法 this.$init.apply(this, arguments); } }
调用父类方法的原理就是找到父类原型类对象上的同名方法,而后使用function.apply方法调用这个方法,同时将this设置为当前调用对象。this
前面DEMO中的$super对象和方法实际是不存在的,$class类定义方法会在类定义时将原代码转换为 this.$super("funcName")的形式。$super方法将返回当前调用链上父类的方法。$super()则会转换为this.$super("$init") 也就是父类的$init构造器方法。prototype
$super方法定义:
JSAClass.prototype.$super = function(){ var func = this.$SuperClass[name];//闭包方法对$SuperClass进行动态赋值 var $this = this; return function(){ return func.apply($this,arguments); }; }
JSAppSugar使用查找父类原型类对象的方式为闭包引用:
var SuperClassProto = SuperClass.prototype;//SuperClass是定义中 $extends对应的类的构造器方法 if(typeof define[key] == "function" && /\$super/.test(define[key])){//函数定义使用了$super时 JSAClass.prototype[key] =( function(defineFunction){//定义一个闭包方法 if(engine.f_redefine) defineFunction = engine.f_redefine(defineFunction);//将$super关键字替换为this.$super('functionName') return function(){ var t = this.$SuperClass; this.$SuperClass = SuperClassProto;//经过闭包引用,将执行当前方法的父类原型赋值到当前对象,以便$super方法快速获取 var result = defineFunction.apply(this,arguments); this.$SuperClass = t; return result; } } )(define[key]); }else{ JSAClass.prototype[key] = define[key]; }
经过闭包引用,实现快速查找当前方法所属类的父类方法。