为什么我不能在Javascript对象中重新定义属性?

Gav*_*ong 37 javascript

我正在创建一个对象Object.create,我想为它添加属性.

> var o = Object.create({});
undefined

> Object.defineProperty(o, "foo", {value: 43, enumerable: true});
{foo: 43}

> o
{foo: 43}

> o.foo
43

> for (var i in o) { console.log(i); }
foo

> Object.keys(o)
['foo']

> Object.defineProperty(o, "foo", {value: 43, enumerable: false });
TypeError: Cannot redefine property: bar
Run Code Online (Sandbox Code Playgroud)

Q1)为什么我不能重新定义财产?

> o.__proto__
{}

> o.prototype
undefined
Run Code Online (Sandbox Code Playgroud)

Q2)为什么原型是空的?为什么这两个值不同,即{}vs undefined

jdp*_*nix 49

您无法重新定义属性,因为Object.defineProperty()默认为不可配置的属性,来自文档:

配置

当且仅当可以更改此属性描述符的类型并且可以从相应对象中删除属性时,才返回true.默认为false.

因此默认为false - 您需要传递它configurable: true以允许它.


Jon*_*ski 32

  1. 通过定义的属性Object.defineProperty()默认为非configurable.

    要允许重新定义或重新配置它们,必须使用此属性设置为定义它们true.

    var o = Object.create({});
    
    Object.defineProperty(o, "foo", {
        value: 42,
        enumerable: true,
        configurable: true
    });
    
    console.log(o); // { foo: 42 }
    
    Object.defineProperty(o, "foo", {
        value: 45,
        enumerable: true,
        configurable: true
    });
    
    console.log(o); // { foo: 45 }
    
    Run Code Online (Sandbox Code Playgroud)
  2. o.prototypeundefined因为对象通常没有prototype属性.

    这种性能上的构造中找到functionS代表new实例由,大致相当于继承:

    function Foo() {}
    
    //  ... = new Foo();
    var bar = Object.create(Foo.prototype);
    Foo.call(bar);
    
    Run Code Online (Sandbox Code Playgroud)

    但是,对象知道它们的原型对象.它们是通过内部[[Prototype]]属性引用的,这__proto__是一个非官方的getter/setter:

    console.log(o.__proto__); // {}
    
    Run Code Online (Sandbox Code Playgroud)

    标准化的阅读方式[[Prototype]]Object.getPrototypeOf():

    console.log(Object.getPrototypeOf(o)); // {}
    
    Run Code Online (Sandbox Code Playgroud)

  • ES6可能会引入[*Object.setPrototypeOf*](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.setprototypeof),被选择所淹没...... (2认同)

Kiw*_*Lau 9

只有当writableconfigure都为 false 时,才会发生“无法重新定义属性”。

如果可写配置为真,错误就会消失。

"use strict"

var obj = {};

Object.defineProperty(obj, "name",
{
   value: "Fundebug",
   writable: false,
   configurable: false
})

Object.defineProperty(obj, "name",
{
   value: "??"
}) // “Uncaught TypeError: Cannot redefine property: name”
Run Code Online (Sandbox Code Playgroud)

因此,jdphenix 和 Jonathan 并不完全正确。


Pra*_*iya 5

Object.defineProperty(o, "foo", {value: 43, enumerable: true});\n
Run Code Online (Sandbox Code Playgroud)\n

此行定义了foo对象的属性o,值为:43 和属性enumerable:true, writable:false, configurable:false。如果该属性存在,defineProperty则更新其标志。否则,它会创建具有给定值和标志的属性;在这种情况下,如果未提供标志,则假定为false

\n

因此,在这里我们使我们的属性不可配置,因为configurable标志(或属性)为false

\n
\n

建立房产non-configurable是一条单向路。我们无法用\nit 改回来defineProperty

\n

准确地说,不可配置性对defineProperty 施加了一些限制:

\n
\n
    \n
  • 可以\xe2\x80\x99t 更改可配置标志。
  • \n
  • 可以\xe2\x80\x99t 更改可枚举标志。
  • \n
  • 可以\xe2\x80\x99t 将 writable: false 更改为 true (反之亦然)。
  • \n
  • 可以\xe2\x80\x99t 更改访问器属性的 get/set(但如果不存在则可以分配它们)。
  • \n
\n

因此,请小心使用configurableflag in defineProperty,如果要更改可枚举可写属性(或标志),请始终在 DefineProperty 中将其设置为 true。一旦将可配置设置为 false,就无法将其设置为 true。

\n