我有一个Object.create的基本包装器用于我们的应用程序。基本上,该过程是在父对象上使用Object.create
,然后.extend({})
为其添加新功能。如果我们需要在父类上调用一个方法,我们只需在方法覆盖中使用ParentClass.myFunc.apply(this, arguments);
。我遇到的问题是当我初始化一个对象并调用父对象的init
函数时,它会覆盖父对象的属性。我怎样才能防止这种情况发生?
这是主要的Object.create包装器:
/**
* Simple wrapper for Object.create and Object.extend
* functionality.
*/
var My_Object = {
/**
* Simple extend function for inheritance
* @param props An object of functions to place in the new object.
* @returns {My_Object}
*/
extend: function(props) {
for(var prop in props)
this[prop] = props[prop];
return this;
},
/**
* Basic function that checks if a function is native or user-created
* @author Yong (http://stackoverflow.com/users/962254/yong)
*
* @param f The function to test if it is native
* @returns {boolean}
*
* @see http://stackoverflow.com/questions/6598945/detect-if-function-is-native-to-browser
*/
isFuncNative: function(f) {
return !!f && (typeof f).toLowerCase() == 'function'
&& (f === Function.prototype
|| /^\s*function\s*(\b[a-z$_][a-z0-9$_]*\b)*\s*\((|([a-z$_][a-z0-9$_]*)(\s*,[a-z$_][a-z0-9$_]*)*)\)\s*{\s*\[native code\]\s*}\s*$/i.test(String(f)));
},
/**
* Simple polyfill wrapper for native Object.create. Using a polyfill
* instead of native incase for some reason consumer would have overwritten
* it with unexpected usage.
*/
create: function(obj) {
// If the browser supports Object.create and hasn't been overwritten,
// use the native version instead of the polyfill
if(My_Object.isFuncNative(Object.create)) {
// If extend hasn't been defined, add it
if(!obj.hasOwnProperty('extend'))
obj.extend = My_Object.extend;
return Object.create(obj);
}
// Create empty function for polyfill
function F(){}
F.prototype = o;
// If extend hasn't been defined, add it
if(!F.prototype.extend)
F.prototype.extend = My_Object.extend;
return new F()
}
};
然后我定义一个基础对象:
var SomeParentObject = {
options: {
a: 'a',
b: 'b'
},
init: function(options) {
this.options = $.extend(this.options, options || {});
return this;
}
};
有些孩子反对:
var ChildObject1 = My_Object.create(SomeParentObject).extend({
init: function() {
SomeParentObject.init.call(this, {b: 'c'});
return this;
}
}).init();
var ChildObject2 = My_Object.create(SomeParentObject).extend({}).init();
现在期望的结果是永远不应该修改SomeParentObject
的选项。我无法弄清楚究竟是什么原因,但我确信这是我做的蠢事。如果您执行了一些基本的console.log
,则可以看到当ChildObject2
有一些要覆盖的选项时,它会覆盖SomeParentObject
,因此会覆盖所有子项。
console.log('<<SomeParentObject.a, SomeParentObject.b>>');
console.log(SomeParentObject.options.a + ', ' + SomeParentObject.options.b);
console.log('<<ChildObject1.a, ChildeObject1.b>>');
console.log(ChildObject1.options.a + ', ' + ChildObject1.options.b);
console.log('<<ChildObject2.a, ChildeObject2.b>>');
console.log(ChildObject2.options.a + ', ' + ChildObject2.options.b);
哪个输出:
<<SomeParentObject.a, SomeParentObject.b>>
a, c
<<ChildObject1.a, ChildeObject1.b>>
a, c
<<ChildObject2.a, ChildeObject2.b>>
a, c
应该输出的是:
<<SomeParentObject.a, SomeParentObject.b>>
a, b
<<ChildObject1.a, ChildeObject1.b>>
a, c
<<ChildObject2.a, ChildeObject2.b>>
a, b
答案 0 :(得分:2)
如果您不喜欢JavaScript中原型设计的工作方式以实现简单的继承和OOP方式,我建议您看一下:https://github.com/haroldiedema/joii
它基本上允许您执行以下操作(以及更多):
// First (bottom level)
var Person = new Class(function() {
this.name = "Unknown Person";
});
// Employee, extend on Person & apply the Role property.
var Employee = new Class({ extends: Person }, function() {
this.name = 'Unknown Employee';
this.role = 'Employee';
this.getValue = function() {
return "Hello World";
}
});
// 3rd level, extend on Employee. Modify existing properties.
var Manager = new Class({ extends: Employee }, function() {
// Overwrite the value of 'role'.
this.role = this.role + ': Manager';
// Class constructor to apply the given 'name' value.
this.__construct = function(name) {
this.name = name;
}
// Parent inheritance & override
this.getValue = function() {
return this.parent.getValue().toUpperCase();
}
});
// And to use the final result:
var myManager = new Manager("John Smith");
console.log( myManager.name ); // John Smith
console.log( myManager.role ); // Manager
console.log( myManager.getValue() ); // HELLO WORLD