JavaScript “类”创建器

摘自《精通 JavaScript 开发》:


小二儿,上代码~

// 定义一个名为 Class 的对象,该对象有一个 create() 方法用于创建新的“类”。我们用闭包来维护内部函数,
// 避免公开暴露这些函数
var Class = (function() {

    // 调用 create() 方法时,它将根据一个对象直接量来定义并返回一个新的“类”,该对象直接量为这个
    // “类”的原型提供了各种公有的属性和方法。一个名为 initialize() 的方法将被作为构造函数来执行。如果
    // 代表父“类”的可选参数 parentPrototype 被传入,则新创建的“类”将成为该父“类”的子类
    function create(classDefinition, parentPrototype) {

        // 定义新“类”的构造函数,如果 classDefinition 对象直接量包含 initialize() 方法,则在构造函数
        // 中使用该方法
        var _NewClass = function() {
                if (this.initialize && typeof this.initialize === 'function') {
                    this.initialize.apply(this, arguments);
                }
            },
            _name;

        // (在继承其他“类”时) 如果传入了一个 parentPrototype 对象,
        // 则子类将继承 parentPrototype 的所有属性和方法
        if (parentPrototype) {
            _NewClass.prototype = new parentPrototype.constructor(); // 创建子类

            for (_name in parentPrototype) {
                if (parentPrototype.hasOwnProperty(_name)) {
                    _NewClass.prototype[_name] = parentPrototype[_name];
                }
            }
        };

        // 通过定义一个函数来创建闭包,然后在闭包中返回另一个函数来替代传入的函数
        // 将传入的函数包装起来,并为当前对象提供一个 __parent() 方法,
        // 以支持父“类”中同名方法的访问,这样就实现了对多太的支持
        function polymorph(thisFunction, parentFunction) {
            return function () {
                var output;

                this.__parent = parentFunction;

                output = thisFunction.apple(this, arguments);

                delete this.__parent;

                return output;
            };
        }

        // 将作为参数传入的“类”定义应用到新创建的“类”上,
        // 覆盖所有 parentPrototype 中已存在的属性和方法
        for (_name in classDefinition) {
            if (classDefinition.hasOwnProperty(_name)) {

                // 如果正在利用多态,即创建和父“类”方法同名的新方法,
                // 我们希望提供一种在子“类”同名方法的简单方式
                if (parentPrototype && parentPrototype[_name] && typeof classDefinition[_name] === 'function') {
                    _NewClass.prototype[_name] = polymorph(classDefinition[_name], parentPrototype[_name]);
                } else {
                    // 如果不需要多态,则直接将 classDefinition 对象直接量中的项映射到新“类”的类型即可
                    _NewClass.prototype[_name] = classDefinition[_name];
                }
            }
        }

        // 确保构造函数属性设置正确,不管是否继承
        // (以防 classDefinition 对象直接量包含名为 constructor 的属性或方法)
        _NewClass.prototype.constructor = _NewClass;

        // 为新创建的“类”自身定义一个 extend() 方法,指向私有的 extend() 函数,这个函数定义在下面,
        // 我们通过此方法可以将当前“类”作为父“类”来创建一个新的子类
        _NewClass.extend = extend;

        return _NewClass;

    }

    // extend() 与 create() 方法相同,不过隐含了一个额外的参数,即用来进行继承的父“类”的原型
    function extend(classDefinition) {
        return create(classDefinition, this.prototype);
    }

    // 用相同的名字将私有的 create() 方法暴露
    return {
        create: create
    };
}());

实现一下:

// 通过 Class.create 定义一个“类”,传入一个对象直接量,该对象包含那些将为新“类”所拥有的公有属性
// 和方法。initialize 方法将成为新类的构造函数
var Accommodation = Class.create({
    isLocked: true,
    isAlarmed: true,
    lock: function() {
        this.isLocked = true;
    },
    unlock: function() {
        this.isLocked = false;
    },
    initialize: function() {
        this.unlock();
    }
});

// Class.create 在创建的所有“类”上添加了一个 extend 方法,我们使用该方法来创建 Accommodation 的子类,
// 以实现简单的继承。父“类”的所有公有方法和属性对子类都可用,如果同名则子类覆盖父类
var House = Accommodation.extend({
    floors: 2,
    lock: function() {

        // 虽然正在用多态来替换父“类”中的同名方法,仍可通过 this.parent() 访问被替换的父“类”方法
        this._parent();
        console.log("Number of floors locked:" + this.floors);
    }
});

// 创建新“类”的对象实例
var myAccommodation = new Accommodation();
var myHouse = new House();
发表评论
* 昵称
* Email
* 网址
* 评论