一種JavaScript類繼承和super方法調用的實現

在設計實現一種Java、Objective-C與JavaScript混合編程的編程風格JSAppSugar時,須要 JavaScript 語言支持類導向的編程風格,然而JavaScript自己是原型導向(Prototype-based)的,所以在JavaScript中也有不少種實現類繼承的方式。這裏介紹一下JSAppSugar中實現類繼承和super方法調用的實現方式。javascript

查看源碼:https://github.com/JSAppSugar/JSA4JS/blob/master/src/JSAppSugar.jsjava

該JS文件設計用於JSA4CocoaJSA4Java中,以實現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);
  }
}

經過$super調用父類方法

調用父類方法的原理就是找到父類原型類對象上的同名方法,而後使用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];
}

經過閉包引用,實現快速查找當前方法所屬類的父類方法。

相關文章
相關標籤/搜索