总的一句话:
当您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]"