在设计实现一种Java、Objective-C与JavaScript混合编程的编程风格JSAppSugar时,需要 JavaScript 语言支持类导向的编程风格,然而JavaScript本身是原型导向(Prototype-based)的,因此在JavaScript中也有很多种实现类继承的方式。这里介绍一下JSAppSugar中实现类继承和super方法调用的实现方式。
查看源码:https://github.com/JSAppSugar/JSA4JS/blob/master/src/JSAppSugar.js
该JS文件设计用于JSA4Cocoa和JSA4Java中,以实现JavaScript与Java、Objective-C混合编程,也可单独使用在普通JavaScript程序中实现类继承和父类方法调用。
类继承编程风格
JSAppSugar编程风格定义一个基础类、子类,以及在子类中调用父类方法。
$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实现类继承的方式采用了原型链方式:
initializing = true;//闭包属性,用于在创建原型链父类对象时避免调用父类的构造器方法
JSAClass.prototype = new SuperClass();//构造原型链
initializing = false;
JSAClass.prototype.constructor = JSAClass;//不是构造原型链继承的必须,设置目的是为了通过类对象查找到类原型
构造器方法的实现(这里只列出了关键代码):
JSAClass = function(){
if(!initializing && this.$init){//initializing为判断是否在构造原型链,如果是则忽略执行构造器方法
this.$init.apply(this, arguments);
}
}
通过$super调用父类方法
调用父类方法的原理就是找到父类原型类对象上的同名方法,然后使用function.apply方法调用这个方法,同时将this设置为当前调用对象。
前面DEMO中的$super对象和方法实际是不存在的,$class类定义方法会在类定义时将原代码转换为 this.$super("funcName")的形式。$super方法将返回当前调用链上父类的方法。$super()则会转换为this.$super("$init") 也就是父类的$init构造器方法。
$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];
}
通过闭包引用,实现快速查找当前方法所属类的父类方法。