For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/year/2022/proposal-accessible-object-hasownproperty.md.
  • 简体中文
  • Accessible Object.prototype.hasOwnProperty S4

    中文标题:可访问的 Object.prototype.hasOwnProperty

    提案概览
    提案速览

    该提案引入了 Object.hasOwn(object, property) 方法,以提供更便捷的方式来检查自有属性,避免了 Object.prototype 方法不可用或被覆盖的问题。它简化了常见的写法,如 Object.prototype.hasOwnProperty.call(object, prop)。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    可访问的 Object.prototype.hasOwnProperty()

    关于 Object.hasOwn() 方法的提案,使 Object.prototype.hasOwnProperty() 更易于访问。

    👋 现在正在收集社区反馈

    请参阅 实现 部分,了解 polyfill 和 codemod,以便今天就在您的代码中使用 Object.hasOwn()

    如果您正在使用 Object.hasOwn(),请在 issue #18 中提供反馈(鼓励正面和/或负面反馈)。

    状态

    此提案目前处于 第 4 阶段

    作者:

    幻灯片:

    动机

    如今,编写这样的代码非常常见(尤其是在库代码中):

    let hasOwnProperty = Object.prototype.hasOwnProperty
    
    if (hasOwnProperty.call(object, "foo")) {
      console.log("has property foo")
    }

    本提案将该代码简化为:

    if (Object.hasOwn(object, "foo")) {
      console.log("has property foo")
    }

    有许多现有的库使这更加方便:

    这是常见做法,因为 Object.prototype 上的方法有时可能不可用或被重新定义。

    Object.create(null)

    Object.create(null) 将创建一个不继承自 Object.prototype 的对象,使得这些方法无法访问。

    Object.create(null).hasOwnProperty("foo")
    // Uncaught TypeError: Object.create(...).hasOwnProperty is not a function

    重新定义 hasOwnProperty

    如果您不直接拥有对象上定义的每个属性,您不能 100% 确定调用 .hasOwnProperty() 就是调用内置方法:

    let object = {
      hasOwnProperty() {
        throw new Error("gotcha!")
      }
    }
    
    object.hasOwnProperty("foo")
    // Uncaught Error: gotcha!

    ESLint no-prototype-builtins

    ESLint 有一个 内置规则 禁止使用像 hasOwnProperty 这样的原型内置方法。

    来自 ESLint 关于 no-prototype-builtins 的文档:


    此规则的不正确代码示例:

    /*eslint no-prototype-builtins: "error"*/
    var hasBarProperty = foo.hasOwnProperty("bar");
    ...

    此规则的正确代码示例:

    /*eslint no-prototype-builtins: "error"*/
    var hasBarProperty = Object.prototype.hasOwnProperty.call(foo, "bar");
    ...

    MDN hasOwnProperty() 建议

    MDN 关于 Object.prototype.hasOwnProperty 的文档包含 建议 不要直接脱离原型链使用它:

    JavaScript 不保护属性名 hasOwnProperty;因此,如果对象可能具有此名称的属性,则有必要使用外部的 hasOwnProperty 来获得正确的结果 [...]

    提案

    本提案添加了一个 Object.hasOwn(object, property) 方法,其行为与调用 hasOwnProperty.call(object, property) 相同

    let object = { foo: false }
    Object.hasOwn(object, "foo") // true
    
    let object2 = Object.create({ foo: true })
    Object.hasOwn(object2, "foo") // false
    
    let object3 = Object.create(null)
    Object.hasOwn(object3, "foo") // false

    实现

    JavaScript 引擎中 Object.hasOwn 的原生实现可用在:

    Object.hasOwn() 的 polyfill 可用在:

    可用于从类似库迁移到 Object.hasOwn() 的 codemod:

    还有一个 eslint 规则用于强制使用 hasOwn 而不是 hasOwnProperty

    问答

    为什么不使用 Object.hasOwnProperty(object, property)

    Object.hasOwnProperty(property) 今天已经存在,因为 Object 本身继承自 Object.prototype,所以定义一个具有不同签名的新方法将是一个破坏性更改。

    为什么命名为 hasOwn

    参见 Issue #3

    为什么不使用 Map 代替对象作为字典?

    摘自 https://v8.dev/features/object-fromentries#objects-vs.-maps

    JavaScript 也支持 Maps,这通常是比普通对象更合适的数据结构。因此,在您完全控制的代码中,您可能会使用 Maps 而不是对象。但是,作为开发人员,您并不总能选择表示形式。有时您操作的数据来自外部 API 或某个库函数,它给您一个对象而不是一个 Map。

    为什么不将此方法放在 Reflect 上?

    Reflect 的目的是包含与每个 Proxy 陷阱一一对应的方法。Proxy 上已经有一个捕获 hasOwnProperty 的方法(getOwnPropertyDescriptor),因此添加额外的陷阱没有意义,所以将此方法放在 Reflect 上也没有意义。

    相关