【译文】 简单的的javascript继承

Simple JavaScript Inheritance

原文:http://ejohn.org/blog/simple-javascript-inheritance/

最近,我在javascript 继承这件事上 花了不少功夫,主要原因是 为了完成我的书 《work-in-progress JavaScript book》在这过程中, 我尝试了各种各样的不同的 可以实现 javascript 继承的方法,在所有我看的方法里,我认为我最喜爱的 是一种基于 base2Prototype的一种实现方式.

我希望可以融汇百家所长,在这些方法中 ,提炼成一个,可复用的 简单的 东西。 它不依赖任何其他东西的,而且即便小白也能看懂。另外 我想这个最终的结果一定是 又简单 又 高度可用的好东东。下面向大家展示一个例子:

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 方法)
  • 必须从一个已有的类上来拓展你要创建的类。
  • 这些所有你创建的‘类’ 都继承自一个共有的祖先‘类’,这样如果你想让你创建的类 可以被其他类继承,那么 他必须继承这个祖先类,或者继承了这个祖先类衍生出来的子类也行。
  • 最有挑战的一点是,那些个被子类同名方法被覆盖了的父类方法,仍然可以通过 this._super()访问的到。

那么用这种方法,让我们实现一个简单的继承:


/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* 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;
    };
})();

初始化

在传统的方式中,为了实现继承,代码可能会像下面这样:

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

有一件非常具有挑战性的事情是,我们需要的仅仅是从 ‘instanceof’ 中获益,而不是去真正的实例化一个Person类,并且执行他的构造函数。

继承他 ,我们仅仅是为了使用它的 原型而已。如果Person 类的构造函数中有一个 非常繁重的任务,那么为了使 Ninjia 类继承 Person类 这次 new Person 是完全没有意义的。

Super Method

当你在实现继承的时候,在创建了 一个Class 后 经常需要访问他 已经被覆盖掉了的父类方法,这就比较麻烦了。一种方法是把他父类的原型完全暴露出来 但这样就丧失了继承的意义。

所以我们在给 子类的原型加属性的时候 都裹了一层方法,动态改变他的 this._super 使他指向当前的同名父类方法, 而他的父类原型也不必暴露出来。

留言:

称呼:*

邮件:

网站:

内容: