odoo中JS继承机制extend与include的区别

admin 2020-7-27 13731

总的一句话:

当您extend时,父类中的实例将保持不变,但新子类中的实例将具有扩展功能。

当您include时,您正在将新特性添加到父类的原型中,这意味着此类的所有实例自动包含扩展行为。


较详细例子:

//基类:
function OdooClass(){}

var initializing = false;
var fnTest = /xyz/.test(function(){xyz();}) ? /\b_super\b/ : /.*/;

/**
 * Subclass an existing class
 *
 * @param {Object} prop class-level properties (class attributes and instance methods) to set on the new class
 */
OdooClass.extend = function() {
    var _super = this.prototype;
    // Support mixins arguments
    var args = _.toArray(arguments);
    args.unshift({});
    var prop = _.extend.apply(_,args);
    // Instantiate a web class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var This = this;
    var prototype = new This();
    initializing = false;
    // Copy the properties over onto the new prototype
    _.each(prop, function(val, name) {
        // Check if we're overwriting an existing function
        prototype[name] = typeof prop[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() {
        if(this.constructor !== OdooClass){
            throw new Error("You can only instanciate objects with the 'new' operator");
        }
        // All construction is actually done in the init method
        this._super = null;
        if (!initializing && this.init) {
            var ret = this.init.apply(this, arguments);
            if (ret) { return ret; }
        }
        return this;
    }
    Class.include = function (properties) {
        _.each(properties, function(val, name) {
            if (typeof properties[name] !== 'function'
                    || !fnTest.test(properties[name])) {
                prototype[name] = properties[name];
            } else if (typeof prototype[name] === 'function'
                       && prototype.hasOwnProperty(name)) {
                prototype[name] = (function (name, fn, previous) {
                    return function () {
                        var tmp = this._super;
                        this._super = previous;
                        var ret = fn.apply(this, arguments);
                        this._super = tmp;
                        return ret;
                    };
                })(name, properties[name], prototype[name]);
            } else if (typeof _super[name] === 'function') {
                prototype[name] = (function (name, fn) {
                    return function () {
                        var tmp = this._super;
                        this._super = _super[name];
                        var ret = fn.apply(this, arguments);
                        this._super = tmp;
                        return ret;
                    };
                })(name, properties[name]);
            }
        });
    };
    // Populate our constructed prototype object
    Class.prototype = prototype;
    // Enforce the constructor to be what we expect
    Class.constructor = Class;
    // And make this class extendable
    Class.extend = this.extend;
    return Class;
};

var UselessClass = OdooClass.extend({
    /**
     * @constructor
     * @param {Object} [mapping] the initial data in the registry
     */
    init: function (mapping) {
        //初始化代码
    },
    useless: function (param) {
        return "UselessClass [useless method]";
    }
});

//extned继承
//给 UselessClass 增加 foo 方法
var AnotherClass = UselessClass.extend({
    foo: function () {
        return "AnotherClass [foo method]";
    },
});

//include继承
//给 AnotherClass 扩展 foo 方法的功能
AnotherClass.include({
    foo: function () {
        return this._super() + "/ThirdClass [foo]";
    },
});

console.log(new UselessClass().useless());
//会打印出 "UselessClass [useless method]"
console.log(new UselessClass().foo());
//会打印出 "Uncaught TypeError: (new UselessClass()).foo is not a function"

console.log(new AnotherClass().useless());
//会打印出 "UselessClass [useless method]"

console.log(new AnotherClass().foo());
//会打印出 "AnotherClass [foo method]/ThirdClass [foo]"



最新回复 (0)
返回