【发布时间】:2015-03-14 21:07:48
【问题描述】:
我的 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,即使对于父方法/属性,除了构造函数。
这是否意味着在使用构造函数模式时它会中断?
当我将公共属性和方法放在构造函数中时,无论是在 BaseClass 还是 SubClass 中,它们都将始终被“标记”为自己的属性/方法。当我将它们附加到各自的原型时,hasOwnProperty 将为它们输出“false”。
无论您将公共方法/属性放在原型还是构造函数本身,它们都可以在子类(--> SubClass2,--> SubClass3)中使用。
我现在唯一能想到的,为什么要将它们附加到原型对象,是因为效率原因,正如here,“定义类方法”-部分所述。为了不为每个构造的实例添加闭包。
值类型应该在原型上声明,但不是实例变量,其初始值取决于构造函数的参数,或构造时的其他状态。 无论声明的位置如何,您都可以覆盖这两个属性/函数。
同时在原型上设置 getter 和 setter,例如设置或获取私有变量,是没有意义的,因为私有变量必须是公共的,以便附加到原型的 getter 和 setter 可以访问.
因此,使用 getter 和 setter 是没有意义的。您可以直接访问公共变量。
我现在必须稍微调整一下我的问题:
我什么时候需要hasOwnProperty,如果实际上应该在原型上声明公共props/functions,这反过来将全部输出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 区分我的子类的哪些属性/函数直接属于它。这是不可能的,因为父原型的所有属性/功能都被复制到子类的原型中:
SubClass.prototype = Object.create(BaseClass.prototype);
使用 hasOwnProperty 时,附加到原型的所有属性/函数都返回“false”。
如果您在 BaseClass 和 SubClass 的构造函数中声明了公共属性/函数,则在为子类上的这些属性调用 hasOwnProperty 时,所有这些属性都会返回“true”。
使用以下语句将这些复制到子类:
BaseClass.call(this, nname);
因此,在迭代 SubClass 类型的 obj 的所有属性时使用 hasOwnProperty,将对原型级别声明的所有属性/函数输出 false,对构造函数级别声明的所有属性/函数输出 true。
现在,我明白了为什么在这个用例中使用 hasOwnProperty 没有意义。
【问题讨论】:
-
你可以嵌入sn-ps!我已删除链接并将您的代码复制粘贴为 sn-p ;)
-
正如答案中指出的那样;你没有使用原型,只在原型、构造函数和继承上设置了更多的实例特定成员:stackoverflow.com/a/16063711/1641941
-
这个演示只是为了展示子类对象的所有属性/函数的hasOwnProperty函数的结果。 sn-p 也包含错误,因为我来回移动代码。但它仍然显示了我想要显示的内容 ;-)
-
@MatíasFidemraizer,我已经更新了我的问题..
-
@Legends 我在我的回答中添加了一个更新,顺便说一句,你一次问自己很多事情,而且我相信你正在努力寻找三足猫。 . :D
标签: javascript prototypal-inheritance hasownproperty coding-efficiency