hasOwnProperty returns true,当检查父对象属性时

hasOwnProperty returns true, when checked against parent object properties

我的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.

现在,当我遍历子class 对象的所有属性时,对于 hasOwnProperty,它们都 return 为真,即使对于父 methods/properties,构造函数除外。

这是否意味着在使用构造函数模式时它会中断?

当我把public属性和方法放在构造函数中时,无论是在BaseClass还是SubClass中,它们总是会被“标记”为自己的properties/methods。当我改为将它们附加到各自的原型时,hasOwnProperty 将为它们输出“false”。

无论你把 public methods/properties 放到原型还是构造函数本身,它们都可以在子类中使用 (--> SubClass2, --> SubClass3) .

我现在唯一能想到的,为什么你应该将它们附加到原型对象,是出于效率原因,如 here,“定义 class 方法”所解释的-部分。为了不为每个构造的实例添加闭包。

值类型应该在原型上声明,但不是例如其初始值取决于构造函数的参数或构造时的其他状态的实例变量。 您可以覆盖两者 properties/functions 而不管它们的声明位置如何。

还在原型上设置 getter 和 setter,例如设置或获取私有变量,这是没有意义的,因为私有变量必须是 public,以便 getter 可以访问和附加到原型的设置器。

因此,使用 getter 和 setter 是没有意义的。您可以直接访问 public 变量。

我现在必须稍微调整一下我的问题:

什么时候需要hasOwnProperty,如果实际上public props/functions 应该声明在原型上,这反过来会输出Object.hasOwnProperty(obj,"prop/func ") --> 错误。给我一个用例,在有意义的时候使用 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 中使用 classical 继承时,我可以区分我的子 properties/functions class ] 直接属于它,使用hasOwnProperty。这是不可能的,因为父原型的所有 properties/functions 都被复制到子类的原型中:

SubClass.prototype = Object.create(BaseClass.prototype);

当使用 hasOwnProperty 时,所有 properties/functions 附加到原型 return“false”。

并且如果您在 BaseClass 和 SubClass 的构造函数中声明了 public properties/functions,则所有这些属性 return "true",当为子类上的这些属性调用 hasOwnProperty 时class.

使用以下语句将这些复制到子类:

BaseClass.call(this, nname);

因此,在遍历 SubClass 类型的对象的所有属性时使用 hasOwnProperty,对于在原型级别声明的所有 properties/functions 输出 false,对于在构造函数级别声明的所有 properties/functions 输出 true。

现在,我明白为什么在这个用例中使用 hasOwnProperty 没有意义了。

检查您是否在 SubClass 的构造函数上调用 BaseClass.call(this),这意味着您正在向 SubClass 实例添加 BaseClass 属性和函数,因为thisSubClass 的实例。

这就是为什么 hasOwnProperty returns true 对于所有属性。

错误的原型...

归根结底,您没有利用 JavaScript 中的原型。

必须属于某个原型的任何实例的函数应该在原型本身中定义。

    var A = function() {};

    A.prototype = {
       doStuff: function() {}
    };

实际上,在构造时定义函数的唯一好处是您可以确保一个对象将始终定义一些 functions/properties,但是一旦对象已经创建,您就可以确保这一点。

对我来说,以下定义属性的方式之间的差别非常小:

var A = function() {};
var instance = new A();
instance.text = "Hello, World!";

// or...

var A = function() {
    this.text = "Hello, World!";
};

var instance = new A();

第一个代码示例在调用构造函数后定义了一个 text 属性,而第二个代码示例在构造函数内部执行它,但在这两种情况下都是 thisinstance 是对同一对象的引用(即 A 的实例)。

使用原型,您可以确保从某些构造函数创建的所有对象都将共享相同的成员,并且这些成员将 继承 并使用 prototype chain 使用。

关于 OP 的更新...

OP说了很多,总结起来就是:

[...] I have to adjust my question a bit now: When do I need hasOwnProperty, if actually public props/functions should be declared on the prototype, which in turn will all output Object.hasOwnProperty(obj,"prop/func") --> false. Give me a use case, when it makes sense, to use hasOwnProperty.

你走错了路...为什么要问自己 何时需要 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";
   }
}

你什么时候使用原型来使用复杂的对象?当您定义 behavior 并且您需要在您的应用程序甚至多个应用程序中重用它时,您还需要在通用需求之上添加更多行为(你好 inheritance).

关于为什么使用 hasOwnProperty...

OP 说:

But why would you use "hasOwnProperty" here, if you want to check the existence of an property? Shouldn't it be: options.mimeType = options.mimeType || "application/json";

网上有很多代码做`options.mimeType =

options.mimeType || "application/json", right, because in JavaScript undefinedevaluates tofalse(ifoptionsdoesn't own amimeTypeproperty returnsundefined`).

以我的拙见,我会使用 hasOwnProperty 因为它 returns 一个 boolean 如果它存在或者它存在并且它具有未定义的值。

例如,选项可以定义为 { mimeType: undefined },有时您想知道 属性 是否存在,即使它的值是 undefinedundefined as false 处理 的情况,如果它是未定义的,无论是否存在,都执行 X,而 hasOwnProperty我想确定它有 属性 或没有 .

那么 为什么我会使用 options.hasOwnProperty 而不是其他方法?。简单:因为,既然语言提供了一种工具来验证某个对象中是否存在 属性,为什么我需要一个技巧? object.hasOwnProperty returns truefalse,我确定 属性 是否存在,即使 属性 有 undefined值。

使用 options.hasOwnProperty("mimeType") 我可以抛出一个 Error 如果它存在并且它有一个 undefined 值。为什么我更喜欢这个?因为我喜欢 fail-fast 概念:如果您给我 属性 和 undefined 值,我倾向于认为您的代码中存在一些错误。定义还是不定义啊朋友!

我将假设 "constructor" 模式,你的意思是在构造函数中分配 this.fn = function (){};this.val = true;

BaseClass.call 上下文中的 this 更改为子 class,因此其中的所有赋值都是在子 class 本身上进行的。严格来说,这实际上根本没有进行任何类型的继承。让我在代码中解释一下。

SubClass.prototype = Object.create(BaseClass.prototype);

在这一行中,您将在子 class 上继承 BaseClass 的原型,这通常意味着继承。但是,BaseClass 的原型与 Function 对象的原型完全相同,SubClass 已经继承自该对象。 this.___ 赋值不会添加到对象的原型中,只会添加到该对象的实例中。要添加到原型,您需要按照 BaseClass.prototype.___ = 'foo'; 的方式执行某些操作,但是,您不想在构造函数中执行此操作,因为每次创建新对象时都会发生该分配。

此外,在您的代码中,调用 SubClass.getName 会引发错误。 name 未在该上下文中定义,仅在 BaseClass 上下文中定义。