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/stage/1/proposal-object-freeze-seal-syntax.md.
  • 简体中文
  • Object.freeze + Object.seal syntax S1

    中文标题:Object.freeze 和 Object.seal 语法

    提案概览
    提案速览

    该提案引入了 Object.freeze 和 Object.seal 的语法,以提高易用性并防止通过原型链进行修改。它草图化了如 {# . #} 用于冻结和 {| . |} 用于密封的语法,适用于对象字面量、数组、解构模式和函数参数。该提案处于早期阶段,包含草图和潜在扩展,尚未成为正式的 TC39 提案。

    Note

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

    Object.freeze 和 Object.seal 语法

    理由

    Object.freeze 和 Object.seal 都是有用的函数,但它们的用法不够便捷,尤其是在处理深层嵌套对象或尝试做复杂操作(如创建冻结对象的超集)时。 此外,即使是冻结的对象也可以通过其原型链被修改:

    > const x = Object.freeze({});
    undefined
    > x.foo
    undefined
    > Object.prototype.foo = 3;
    3
    > x.foo
    3

    为了防止这种情况,你可以使用 Object.freeze({ __proto__: null })Object.freeze(Object.assign(Object.create(null), {})) 来确保冻结的 对象不能通过其原型链被修改。

    > const x = Object.freeze({ __proto__: null });
    undefined
    > x.foo
    undefined
    > Object.prototype.foo = 3;
    3
    > x.foo
    undefined

    此外,在其他地方使用这些语法也会很有用。例如,密封解构表达式或冻结函数参数以创建不可变的绑定。

    草图

    冻结对象的基本语法

    const foo = {#
      a: {#
        b: {#
          c: {#
            d: {#
              e: [# "some string!" #]
            #}
          #}
        #}
      #}
    #}
    点击此处查看脱糖版本
    const foo = Object.freeze({
      __proto__: null,
      a: Object.freeze({
        __proto__: null,
        b: Object.freeze({
          __proto__: null,
          c: Object.freeze({
            __proto__: null,
            d: Object.freeze({
              __proto__: null,
              e: Object.freeze([ "some string!" ])
            })
          })
        })
      })
    })

    密封对象的基本语法

    const foo = {|
      a: {|
        b: {|
          c: {|
            d: {|
              e: [| "some string!" |]
            |}
          |}
        |}
      |}
    |}
    点击此处查看脱糖版本
    const foo = Object.seal({
      __proto__: null,
      a: Object.seal({
        __proto__: null,
        b: Object.seal({
          __proto__: null,
          c: Object.seal({
            __proto__: null,
            d: Object.seal({
              __proto__: null,
              e: Object.seal(["some string!"])
            })
          })
        })
      })
    })

    密封函数的解构选项对象

    function ajax({| url, headers, onSuccess |}) {
      fetch(url, { headers }).then(onSuccess)
    }
    ajax({ url: 'http://example.com', onsuccess: console.log })
    // throws TypeError('cannot define property `onsuccess`. Object is not extensible')
    点击此处查看脱糖版本
    function ajax(_ref1) {
      const _ref2 = Object.seal({ url: undefined, headers: undefined, onSuccess: undefined })
      Object.assign(_ref2, _ref1)
      let url = _ref2.url
      let headers = _ref2.headers
      let onSuccess = _ref2.onSuccess
    
      fetch(url, { headers }).then(onSuccess)
    }
    ajax({ url: 'http://example.com', onsuccess: console.log })
    // throws TypeError('cannot define property `onsuccess`. Object is not extensible')

    冻结函数的解构选项对象

    function ajax({# url, headers, onSuccess #}) {
      url = new URL(url) // throws TypeError('cannot assign to const `url`')
      fetch(url, { headers }).then(onSuccess)
    }
    ajax({ url: 'http://example.com', onSuccess: console.log })
    点击此处查看脱糖版本
    function ajax(_ref1) {
      const _ref2 = Object.seal({ url: undefined, headers: undefined, onSuccess: undefined }) // seal now, const later
      Object.assign(_ref2, _ref1)
      const url = _ref2.url
      const headers = _ref2.headers
      const onSuccess = _ref2.onSuccess
    
      url = new URL(url) // throws TypeError('cannot assign to const `url`')
      fetch(url, { headers }).then(onSuccess)
    }
    ajax({ url: 'http://example.com', onSuccess: console.log })

    潜在的扩展 - 草图

    密封的函数参数绑定

    function add(| a, b |) {
      return a + b
    }
    add(2, 2, 2) === 6
    // throws TypeError('invalid third parameter, expected 2`)
    点击此处查看脱糖版本
    function add(_1, _2) {
      if (arguments.length > 2) {
        throws TypeError('invalid third parameter, expected 2')
      }
      let a = arguments[0]
      let b = arguments[1]
    
      return a + b
    }
    add(2, 2, 2) === 6
    // throws TypeError('invalid third parameter, expected 2`)

    冻结的函数参数绑定

    function add1(# a #) {
      a += 1 // throws TypeError `invalid assignment...`
      return a
    }
    add1(1) === 2
    点击此处查看脱糖版本
    function add1(_1) {
      if (arguments.length > 1) {
        throws TypeError('invalid second parameter, expected 1')
      }
      const a = arguments[0]
    
      a += 1 // throws TypeError `invalid assignment...`
      return a
    }
    add1(1) === 2

    将语法扩展到一般解构以获得更好的类型安全性

    const foo = { a: 1, b: 2 }
    const {| a, b, c |} = foo
    // Throws TypeError 'invalid assignment to unknown property c'
    点击此处查看脱糖版本
    const foo = { a: 1, b: 2 }
    if (!('a' in foo)) throw new TypeError('invalid assignment to unknown property a')
    const a = foo.a
    if (!('b' in foo)) throw new TypeError('invalid assignment to unknown property b')
    const b = foo.b
    if (!('c' in foo)) throw new TypeError('invalid assignment to unknown property c')
    const c = foo.c
    // Throws TypeError 'invalid assignment to unknown property c'