【问题标题】:When is `hasOwnProperty` not required?什么时候不需要`hasOwnProperty`?
【发布时间】:2017-05-23 04:42:58
【问题描述】:

什么时候不需要hasOwnProperty

JavaScript: The Good Parts 一书包含以下内容,其中说“它通常是必要的”:

另一种形式(称为for in)枚举对象的属性名称(或键)。 在每次迭代中,来自 object 的另一个属性名称字符串被分配给 变量

通常需要测试object.hasOwnProperty(variable)来判断是否 属性名称确实是对象的成员,或者是在原型上找到的 链。

for (myvar in obj) {
 if (obj.hasOwnProperty(myvar)) {
 ...
 }
}

更具体地说,我想枚举一个简单的类字典对象的属性,该对象是使用 Javsacript 对象文字语法创建的,例如:

var foo = { 'bar': 'baz' };

或使用JSON.parse创建的类似对象:

var foo = JSON.parse("{ 'bar': 'baz' }");

当我对foo 对象执行for in 时,我应该使用hasOwnProperty 吗?

假设这个 javascript 作为复杂网页的一部分在随机浏览器中运行。

答案是,“实际上可能/通常没有必要。理论上,如果某些框架或库通过更改 Object.prototype 添加属性,则可能是必要的,但像这样更改 Object.prototype 将是一个侵入性的坏事任何受人尊敬的框架都不太可能做的实践”?

【问题讨论】:

  • 您可以使用Object.keys(obj).forEach(key => ...),因为它只会获得自己的属性。
  • 如果您认为需要支持 IE8 或更早版本,我也会推荐 Object.keys - 使用适当的 polyfill
  • 我相信某些网页确实更改了Object.prototype,或类似的重要内容。我曾经发现当我的 JavaScript 在 SalesForce 中运行时,for.. in 迭代的不仅仅是我的数据结构的预期项目(虽然不记得这是一个数组还是对象)。
  • @Birchlabs 是的,但是在 ES5+ 中,该代码应该使用 Object.defineProperty 来使这些添加不可枚举,以便它们不 i> 在你做for ... in时出现
  • @ChrisW 上面写着“不要扩展Object.prototype”。那是正确的,但现在(正确完成)它是完全安全的。

标签: javascript hasownproperty


【解决方案1】:

恕我直言,在现代 JS 解释器中,它几乎 [*] 从来不需要,尤其是对于仅用作字典的普通对象。

没有它,jQuery 管理得很好,因为人们已经知道不安全地将可枚举属性添加到 Object.prototype 是一个坏主意。

当然,ES5 允许您使用Object.definePropertyObject.prototype 添加不可枚举的 属性。

[*] 上述情况的例外情况是,如果您正在编写专门检查原型链的代码,并且确实需要知道可枚举属性是否被继承

【讨论】:

  • 在 2008 年写这本书的时候,出于某种原因“通常有必要”吗?
  • @ChrisW 很可能,是的 - 那时人们确实Object.prototype添加了东西,而您没有创建不可枚举属性的选项
【解决方案2】:

hasOwnProperty 在“理智、现代、环境”1 中迭代普通对象2 时不需要:这个假设意味着限制旧版浏览器支持。

所有标准的Object 属性在很长一段时间内都是不可枚举的,而新的核心方法也一直是不可枚举的。


1 如果代码决定添加到 Object.prototype,除了 polyfill 之外,这也是值得怀疑的,它应该将其添加为不可枚举的属性。添加新的可枚举属性违反了“健全的环境”约束。 IE 9+(和 FF/Chrome/Safari 等)支持 Object.defineProperty 足以完成此任务。 IE 8 没有也违反了“现代”约束。

2 数组不符合普通对象的条件。对于大多数数组迭代来说,使用for..in 也是不明智的。

【讨论】:

  • 同意 - 这本书的建议可能与使用向 Object.prototype 添加可枚举属性的 polyfills 的上下文相关。当然,为Object.keys(为你调用hasOwnProperty)添加一个polyfill可以解决这个问题。
【解决方案3】:

仅在绝对可预测的情况下才需要,这意味着 - 几乎从不。

在 ECMAScript 5.1 中,添加了Object.create,它可以创建 具有指定[[Prototype]] 的对象。 Object.create(null) 是一个 用于创建将用作 Map 的对象的通用模式。这 当假定对象将具有 来自Object.prototype 的属性。此规则可防止调用某些 Object.prototype 直接来自对象的方法。

此外,对象可以具有隐藏内置函数的属性 Object.prototype,可能导致意外行为或 拒绝服务安全漏洞。例如,它将是 网络服务器解析来自客户端的 JSON 输入并调用是不安全的 hasOwnProperty 直接在结果对象上,因为恶意 客户端可以发送一个 JSON 值,如 {"hasOwnProperty": 1} 并导致 服务器崩溃。

为避免此类细微错误,最好始终调用这些 来自Object.prototype 的方法。例如,foo.hasOwnProperty("bar") 应替换为Object.prototype.hasOwnProperty.call(foo, "bar")

【讨论】:

    猜你喜欢
    • 2015-12-02
    • 1970-01-01
    • 2012-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多