介绍一个简单的JavaScript类框架

在写work-in-progress JavaScript book一书时,对于javascript继承体系,我花费了相当的时间,并在该过程中研究了各种不同的模拟经典类继承的方案。这些技术方案中,我最为推崇的是base2与Prototype的实现。

从这些方案中,应该能提炼出一个具有其思想内涵的框架,该框架须具有简单、可重用、易于理解并无依赖等特点,其中简单性与可用性是重点。以下是使用示例:
 

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

有几点需要留意:

    构造函数须简单(通过init函数来实现),

    新定义的类比须继承于已有的类,

    所有的‘类'都继承于始祖类:Class,因此如果要创建一个全新的类,该类必须为Class的子类,

    最具挑战的一点:父类的被覆写方法必须能访问到(通过配置上下文环境)。

    在上面的示例中,你能发现通过this._super()来调用Person父类的init()和dance()方法。

对结果相当满意:使类的定义结构化,保持单一继承,并且能够调用超类方法。

简单的类创建与继承

下面为其实现(便于阅读并有注释),大概25行左右。欢迎并感谢提出建议。
 

/* Simple JavaScript Inheritance * By John Resig * MIT Licensed. */ // 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)”与“创建_super方法”最为棘手。接下来,我会对此做简要的介绍,使得大家对其实现机制能更好的理解。

初始化

为了说明函数原型式的继承方式,首先来看传统的实现过程,即将子类的prototype属性指向父类的一个实例。如下所示:


function Person ( ) { } function Ninja ( ) { } Ninja. prototype = new Person ( ); // Allows for instanceof to work: (new Ninja()) instanceof Person

然而,这里具有挑战性的一点,便是我们只想要得到‘是否实例(instatnceOf)'的效果,而不需要实例一个 Person并调用其构造函数所带来的后果。为防止这一点,在代码中设置一个bool参数initializing,只有在实例化父类并将其配置到子类的prototype属性时, 其值才为true。这样处理的目的是区分开真正的实例化与设计继承时这两种调用构造函数之间的区别,进而在真正实例化时调用init方法:
 

if ( !initializing ) this.init.apply(this, arguments);

值得特别注意的是,因为在init函数中可能会运行相当费资源的代码(如连接服务器,创建DOM元素等,谁也无法预测),所以做出区分是完全必要的。

超类方法(Super Method)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgdfwp.html