04. Object Properties

Access to properties

Общий синтаксис:

const object = {
  foo: "bar",
  age: 42,
  baz: { myProp: 12 }
};

object.foo; // "bar"
object["age"]; // 42
object.foo = "baz";

В JS можно обратиться к любому свойству объекта, даже если его нет. Ошибки не будет. Но если свойство не существует, то вернется undefined.

Попытка присвоить значение свойству p объекта o потерпит неудачу в следующих случаях:

  • Объект o имеет собственное свойство p, доступное только для чтения: нельзя изменить значение свойства, доступного только для чтения.

  • Объект o имеет унаследованное свойство p, доступное только для чтения: унаследованные свойства, доступные только для чтения, невозможно переопределить собственными свойствами с теми же именами.

  • Объект o не имеет собственного свойства p; объект o не наследует свойство p с методами доступа и атрибут extensible объекта o имеет значение false.

Safe property access

Для безопасного доступа к полям объекта можно использовать операторы || и && и ??. Разница между ними в том, что || и && выполняют более общую проверку на truthy/falsy, тогда как ?? только на null или undefined.

const o = { x: 1, y: { z: 2 } };
o.x || 3; // 1
o.z || 3; // 3
o.y && o.y.x; // undefined
o.y && o.y.z; // 2
(o.y && o.y.x) || 4; // 4

Optional chaining в ES2020 позволяет обращаться к вложенным полям объекта при условии, что предыдущие поля в пути определены:

// Before
const hashtags = books.entities && books.entities.hashtags

// Optional chaining
const hashtags = books?.entities?.hashtags

Property access in the spec

The operator for getting and setting properties uses the internal operation ToPropertyKey(), which works as follows:

  • Convert the operand to a primitive via ToPrimitive() with the preferred type String:

    • A primitive value is returned as it is.

    • Otherwise, the operand is an object. If it has a method [@@toPrimitive](), that method is used to convert it to a primitive value. Symbols have such a method, which returns the wrapped symbol.

    • Otherwise, the operand is converted to a primitive via toString() – if it returns a primitive value. Otherwise, valueOf() is used – if it returns a primitive value. The preferred type String determines that toString() is called first, valueOf() second.

    • Otherwise, a TypeError is thrown.

  • If the result of the conversion is a symbol, return it.

  • Otherwise, coerce the result to string via ToString().

Operator delete

Единственным способом удалить пару ключ-значение из объекта является оператор delete. Если присвоить ключу значение undefined, то мы удалим только значение, ключ останется в объекте. Если не использовать delete, то ключ будет встречаться при перечислении ключей объекта.

  • Оператор delete удаляет только собственные свойства и не удаляет унаследованные.

  • Нельзя удалить non-configurable свойство.

  • Чтобы удалить унаследованное свойство, необходимо удалять его в объекте-прототипе, в котором оно определено. Такая операция затронет все объекты, наследующие этот прототип.

const mycar = { make: "Honda", model: "Accord", year: 1998 };
delete mycar.make;
"make" in mycar; // returns false

Оператор delete возвращает false если удаляемое свойство является свойством объекта, но не может быть удалено. В остальных случаях оператор возвращает false.

На деле, оператор delete не связан с управлением памятью. Оператор delete полностью удаляет некоторое свойство из указанного объекта, но если оно есть в прототипе -- устанавливается его значение из прототипа. Оператор delete позволяет удалять свойства глобального объекта, но не позволяет удалять переменные.

An algorithm for delete is specified roughly like this:

  • If operand is not a reference, return true

  • If object has no direct property with such name, return true (where, as we now know, object can be Activation object or Global object)

  • If property exists but has DontDelete, return false

    Otherwise, remove property and return true

Check property existence

Выполнить проверку наличия свойства в объекте можно одним из следующих способов:

Operator in

Оператор in требует, чтобы в левом операнде ему было передано имя свойства (в виде строки) и объект в правом операнде. Он возвращает true, если объект имеет собственное или унаследованное свойство с этим именем. В противном случае возвращает undefined.

const c = { make: "Honda", model: "Accord", year: 1998 };
"make" in c; // returns true
"model" in c; // returns true
"google" in c; // returns undefined

obj.hasOwnProperty()

Метод hasOwnProperty() объекта проверяет, имеет ли объект собственное свойство с указанным именем. Для наследуемых свойств он возвращает false.

const o = {};
o.prop = "exists";
o.hasOwnProperty("prop"); // returns true
o.hasOwnProperty("toString"); // returns false
o.hasOwnProperty("hasOwnProperty"); // returns false

obj.propertyIsEnumerable()

Метод propertyIsEnumerable() накладывает дополнительные ограничения по сравнению с hasOwnProperty(). Он возвращает true, только если указанное свойство является собственным свойством, атрибут enumerable которого имеет значение true.

var a = ["is enumerable"];
a.propertyIsEnumerable(0); // returns true
a.propertyIsEnumerable("length"); // returns false
Math.propertyIsEnumerable("random"); // returns false
this.propertyIsEnumerable("Math"); // returns false

Last updated