Подтвердить что ты не робот

Почему я не могу переопределить свойство в объекте 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

Q1) Почему я не могу переопределить свойство?

> o.__proto__
{}

> o.prototype
undefined

Q2) Почему прототип пуст? И почему эти 2 значения отличаются друг от друга, т.е. {} vs undefined?

4b9b3361

Ответ 1

Вы не можете переопределить свойство, потому что Object.defineProperty() по умолчанию неконфигурируемые свойства, из docs:

конфигурируемый

true тогда и только тогда, когда тип этого дескриптора свойства может быть изменен и если свойство может быть удалено из соответствующего объекта.     По умолчанию false.

Итак, это значение по умолчанию - false - вам нужно передать его configurable: true, чтобы разрешить его.

Ответ 2

  • Свойства, определенные через 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 }
    

  • o.prototype - undefined, поскольку объекты обычно не имеют свойств prototype.

    Такие свойства найдены в конструкторе function для экземпляров new для наследования, примерно эквивалентного:

    function Foo() {}
    
    //  ... = new Foo();
    var bar = Object.create(Foo.prototype);
    Foo.call(bar);
    

    Объект, однако, знает об их объектах прототипа. Они ссылаются на внутреннее свойство [[Prototype]], которое __proto__ является/является неофициальным получателем/установщиком:

    console.log(o.__proto__); // {}
    

    Стандартизованный способ чтения [[Prototype]] заключен в Object.getPrototypeOf():

    console.log(Object.getPrototypeOf(o)); // {}
    

Ответ 3

Только когда оба записываемых и настраиваемых имеют значение false, произойдет "Невозможно переопределить свойство".

Если значение доступное для записи или настраиваемое равно true, ошибка исчезнет.

"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'

Поэтому jdphenix и Jonathan не совсем верны.

Ответ 4

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

Эта строка определяет свойство foo для объекта o со значением: 43 и атрибутами enumerable:true, writable:false, configurable:false. Если свойство существует, defineProperty обновляет свои флаги. В противном случае он создает свойство с заданным значением и флагами; в этом случае, если флаг не указан, он принимается ложным.

Итак, здесь мы делаем наше свойство неконфигурируемым, поскольку флаг (или атрибут) configurable равен false.

Создание собственности non-configurable является дорогой с односторонним движением. Мы не можем изменить это обратно с defineProperty.

Чтобы быть точным, неконфигурируемость накладывает несколько ограничений на defineProperty:

  • Не могу изменить настраиваемый флаг.
  • Не могу изменить перечисляемый флаг.
  • Не могу изменить запись: ложь на истину (наоборот работает).
  • Cantchange get/set для свойства аксессора (но может присваивать их при отсутствии).

Поэтому будьте осторожны с флагом configurable в defineProperty, всегда устанавливайте его в true в defineProperty, если вы хотите изменить перечисляемые и доступные для записи атрибуты (или флаг). Как только вы установите настраиваемое значение false, вы не сможете установить его в значение true.