我的 JavaScript 代码:
console.clear();
function BaseClass(nname) {
var name = nname;
this.bc_PublicProperty = "DefaultValue_BaseClass";
this.bc_getName = function GetName() {
return name;
};
this.bc_setName = function SetName(nname) {
name = nname;
};
}
function SubClass(nname) {
BaseClass.call(this, nname);
this.sc_PublicProperty = "DefaultValue_SubClass";
this.sc_getName = function GetName() {
return name;
};
this.sc_setName = function SetName(nname) {
name = nname;
};
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
var bc = new BaseClass("Anton");
var sc = new SubClass("Bernd");
console.log("hasOwnProperty check on subclass object 'sc' returns true for Method 'bc_getName'");
for (var pro in sc) {
console.log("Is " + pro + " own property of subclass: --> " + Object.hasOwnProperty.call(sc, pro));
}
我有两个对象(BaseClass 和 SubClass)。一个使用构造函数模式从另一个继承,如 explained on MDN 。
现在,当我遍历子类对象的所有属性时,它们都为 hasOwnProperty 返回 true,即使对于父方法/属性,构造函数除外。
这是否意味着在使用构造函数模式时它会中断?
当我在构造函数中放置公共(public)属性和方法时,无论是在 BaseClass 还是 SubClass 中,它们将始终被“标记”为自己的属性/方法。当我将它们附加到各自的原型(prototype)时,hasOwnProperty 将为它们输出“false”。
无论您是将公共(public)方法/属性放入原型(prototype)还是构造函数本身,它们都可以在子类(--> SubClass2,--> SubClass3)中使用。
我现在唯一能想到的,为什么要将它们附加到原型(prototype)对象,是因为效率原因,如 here ,“定义类方法”部分所述。为了不为每个构造的实例添加闭包。
值类型应该在原型(prototype)上声明,但不是例如初始值依赖于构造函数的参数或构造时的其他状态的实例变量。
您可以覆盖这两个属性/函数,而不管它们的声明位置。
同样在原型(prototype)上设置 getter 和 setter,例如设置或获取私有(private)变量,也是没有意义的,因为私有(private)变量必须是公开的,以便附加到原型(prototype)的 getter 和 setter 可以访问。
因此,使用 getter 和 setter 是没有意义的。您可以直接访问公共(public)变量。
我现在必须稍微调整一下我的问题:
我什么时候需要hasOwnProperty,如果实际上应该在原型(prototype)上声明公共(public) Prop /函数,这反过来将全部输出Object.hasOwnProperty(obj,"prop/func") --> false。给我一个用例,当它有意义时,使用 hasOwnProperty。
console.clear();
var l = function(v) {
console.log(v);
};
function BaseClass(nname) {
this.bc_nameProp = nname;
this.bc_ownFunc = function() {
l("bc_ownFunc of BaseClass called");
};
this.bc_getName = function GetName() {
return this.bc_nameProp;
};
}
BaseClass.prototype.bc_getName = function GetName() {
return this.bc_nameProp;
};
BaseClass.prototype.bc_PublicProperty = "DefaultValue_BaseClass";
BaseClass.prototype.bc_setName = function SetName(nname) {
bc_nameProp = nname;
};
function SubClass(nname) {
BaseClass.call(this, nname);
this.sc_setName = function SetName(nname) {
bc_nameProp = nname;
};
this.bc_getName = function GetName() {
return "xyz";
};
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
SubClass.prototype.sc_getName = function GetName() {
return this.bc_nameProp;
};
SubClass.prototype.sc_PublicProperty = "DefaultValue_SubClass";
var bc = new BaseClass("Anton");
var sc = new SubClass("Bernd");
l("----- iterating over BaseClass properties ------");
l("");
for (var pro in bc) {
l("Is " + pro + " own property of BaseClass: --> " + Object.hasOwnProperty.call(bc, pro));
}
l("");
l("----- iterating over SubClass properties ------");
l("");
for (var p in sc) {
l("Is " + p + " own property of subclass: --> " + Object.hasOwnProperty.call(sc, p));
}
l(bc.bc_getName());
l(sc.bc_getName());
l(sc.sc_getName());
解决方案
当我问这个问题时,我的观点是,在 JavaScript 中使用经典继承时,我可以使用 hasOwnProperty 区分子类的哪些属性/函数直接属于它。这是不可能的,因为父原型(prototype)的所有属性/函数都被复制到子类的原型(prototype)中:
SubClass.prototype = Object.create(BaseClass.prototype);
使用 hasOwnProperty 时,所有附加到原型(prototype)的属性/函数都返回“false”。如果您在 BaseClass 和 SubClass 的构造函数中声明了公共(public)属性/函数,则在为子类上的这些属性调用 hasOwnProperty 时,所有这些属性都返回“true”。
使用以下语句将它们复制到子类:
BaseClass.call(this, nname);
因此,在迭代类型为 SubClass 的 obj 的所有属性时使用 hasOwnProperty,将为在原型(prototype)级别声明的所有属性/函数输出 false,为在构造函数级别声明的所有属性/函数输出 true。现在,我明白为什么在这个用例中使用 hasOwnProperty 没有意义。
最佳答案
检查您是否在 BaseClass.call(this)
的构造函数上调用 SubClass
,这意味着您正在向 BaseClass
实例添加 SubClass
属性和函数,因为 this
是 SubClass
的一个实例。
这就是 hasOwnProperty
为所有属性返回 true
的原因。
错误的原型(prototype)...
归根结底,您并没有利用 JavaScript 中的原型(prototype)。
必须是某个原型(prototype)的任何实例的一部分的函数应该在原型(prototype)本身中定义。
var A = function() {};
A.prototype = {
doStuff: function() {}
};
实际上,在构造时定义函数的唯一好处是您可以确保对象始终定义一些函数/属性,但是一旦对象已经创建,您就可以确保这一点。对我来说,以下定义属性的方法之间存在很小的差异:
var A = function() {};
var instance = new A();
instance.text = "Hello, World!";
// or...
var A = function() {
this.text = "Hello, World!";
};
var instance = new A();
第一个代码示例在构造函数被调用后定义了一个 text
属性,而第二个代码示例在构造函数内部执行它,但在这两种情况下, this
或 instance
都是对同一对象(即 A
的实例)的引用。使用原型(prototype),您可以确保从某个构造函数创建的所有对象都将共享相同的成员,并且这些成员将使用 prototype chain 被继承和使用。
关于 OP 的更新...
OP说了很多,但总结说:
你走错了路……为什么在需要
hasOwnProperty
时问自己?问问自己什么时候需要可重用性较低的简单对象,或者什么时候需要真正的可重用性。 hasOwnProperty
与此问题无关。当您使用文字对象(即使用
{}
语法声明为原样的对象)时?当你需要字典、参数映射、值对象时......这里你喜欢 hasOwnProperty
因为通常你的代码接收参数看起来像这样:function X(uri, options) {
if(typeof options != "undefined") {
// For example, we set a default value if options has no
// mimeType property...
options.mimeType = options.hasOwnProperty("mimeType") ? options.mimeType : "application/json";
}
}
什么时候使用原型(prototype)来使用复杂对象?当您定义行为并且需要在您的应用程序甚至多个应用程序中重用它时,您还需要在通用需求(hello 继承)之上添加更多行为。关于为什么使用
hasOwnProperty
...OP 说:
网上有很多代码做`options.mimeType =
以我的拙见,我会使用
hasOwnProperty
因为它返回一个 boolean
如果它存在或者它存在并且它没有定义为值。例如,选项可以定义为
{ mimeType: undefined }
,有时您想知道该属性是否存在,即使它具有 undefined
作为值。 undefined
作为 false
处理未定义的情况,无论它是否存在,都执行 X,而 hasOwnProperty
是我想确定它是否具有该属性。那么 为什么我要使用
options.hasOwnProperty
而不是其他方法? 。简单:因为语言提供了一个工具来验证某个对象中是否存在属性,为什么我需要一个技巧? object.hasOwnProperty
返回 true
或 false
,我确定该属性是否存在,即使该属性具有 undefined
值。使用
options.hasOwnProperty("mimeType")
我可以抛出一个 Error
如果它存在并且它有一个 undefined
值。为什么我更喜欢这个?因为我喜欢 fail-fast 概念:如果你给我 undefined
值的属性,我倾向于认为你的代码中有一些错误。定义与否,我的 friend !关于javascript - hasOwnProperty 在检查父对象属性时返回 true,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29054218/