简单的JavaScript继承
我想萃取有关继承技术的精华到一个简单、可重用、容易理解且不会有任何依赖的形式实现。此外,我也想让这个结果简单而且非常有用。这有一个我想要的效果的例子:
var Person = Class . extend ( {
init: function ( isDancing ) {
this . dancing = isDancing;
} ,
dance: function ( ) {
return this . dancing ;
}
} ) ;
var Ninja = Person.extend({
init: function(){
this._super( false );
},
dance: function(){
// Call the inherited version of dance()
return this._super();
},
swingSword: function(){
return true;
}
});
var p = new Person(true);
p.dance(); // => true
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class
这个实现中有几点需要注意:
1、创建一个构造类必须要简单(这种情况下简单的提供一个init方法就能起作用);
2、要创建一个新的‘class’就必须扩展(sub-class )已经存在的类;
3、所有的 ‘classes’都从一个祖先继承而来:Class。因此如果你想创建一个新类分支,这个新类分支就必定是 Class的子类;
4、最有挑战一点的是:获取被 覆写 了的但 必须被提供 的方法(这些方法的上下文被正确设置)。上面用this._super()方法调用了Person父类原来的init()和dance()方法说明了这一点。
我对这个结果还是很满意的:它有助于增强‘classes’作为一个构造(structure)的概念,保持了简单的继承,并允许对父类的方法调用。
简单的类构造和继承
这有一个上面代码的实现(规模适度而且评论颇佳)-上下代码25行左右。反馈很好且被广泛接受。
// Inspired by base2 and Prototype
( function ( ) {
var initializing = false , fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/ ;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
在我看来,最棘手的两个问题是 "initializing/Don't call init"和"create super method"。我想简单的涉及一下这些,以使你对这个方法中完成了什么有一个更好的理解。
初始化
为了用一个函数的prototype来模仿继承,我们用传统的技术来创建一个父类函数的实例化并把它分配给子类的prototype。不考虑上面的内容的话其实现大抵像这样:
function Person ( ) { }
function Ninja ( ) { }
Ninja. prototype = new Person ( ) ;
// Allows for instanceof to work:
( new Ninja ( ) ) instanceof Person
这里面的挑战是,我们需要利用instanceof的好处,而不是仅仅考虑实例化Person父类以及运行他的构造函数 的消耗。 为了中和这两者的效应,在我们的代码中有一个变量 initializing,无论什么时候我们想实例化一个类(唯一的目的是)来作为prototype的值,该变量都被设置为true。
因此当谈到实际的构造函数的时候,我们要确信我们不是在一个初始化模式,而是有条件的执行init方法:
if ( !initializing )
this . init . apply ( this , arguments ) ;
尤其重要的是,init方法可以运行各种消耗很大的启动代码(连接到服务器,创建DOM元素,谁知道呢)所以绕过这个最终的工作会很有好处。
super 方法
当你在做继承的时候,你创建一个类从父类中继承功能,一个常见的要求是你要能获取已经被你重写的方法。结果,在这个特别的实现中是一个新的临时方法._super。这个方法是唯一可以通过子类的方法来引用父类的相同方法的途径。
比如,如果你想通过这项技术来调用父类的构造函数,你可以这样做:
var Person = Class . extend ( {
init: function ( isDancing ) {
this . dancing = isDancing;
}
} ) ;
var Ninja = Person.extend({
init: function(){
this._super( false );
}
});
var p = new Person(true);
p.dancing; // => true
var n = new Ninja();
n.dancing; // => false
实现这一功能是一个多步的过程。开始的时候,注意,我们用来扩展一个已经存在的类的对象字面量 (比如被传入到Person.extend里的那一个)需要merge到基础的new Person实例(该实例的结构在前面已经被描述过)。在这个 merge 的
补充:web前端 , JavaScript ,