Взлом Javascript Objects — I

Большинство из нас имеют дело с Объектами практически каждый день, и это одна из наиболее часто используемых структур данных. Но немногие из нас могут знать, что можно также управлять поведением свойств объекта или, можно сказать, «взламывать» свойства объектов 😂.

В этом посте мы рассмотрим некоторые внутренние свойства объектов, которые могут помочь в достижении этой цели, а также проведем веселую викторину в конце поста 😉.

Прежде чем мы погрузимся во внутреннюю суть object, давайте начнем с основ.

Что такое объекты?

Объекты — это коллекция свойств, где каждое свойство имеет ключ и значение.

Объекты могут быть созданы в трех формах👇🏻

  1. Нотация literal с curly braces {}. Это наиболее часто используемый синтаксис.

  2. Использование конструктора Object. Класс Object представляет собой одну из структур данных в Javascript. Вряд ли возникнет необходимость использовать эту форму при создании объектов, но все же полезно знать 🙂 .

  3. Мы не будем вдаваться в подробности о третьей форме, но расскажем о ней позже в этом посте 🙂 .

Настройка поведения свойств объекта

Итак, начать работу с объектами довольно просто, но вот дальше начинается интересный факт — поведение свойств объекта также можно настраивать.

Давайте посмотрим, какие настройки возможны 👀.

Класс Object имеет статический метод defineProperty, который позволяет добавить новое свойство или обновить существующее свойство объекта, а также контролировать поведение свойства. Доступ к статическим свойствам осуществляется напрямую через класс, экземпляры не нужно создавать для доступа к статическим свойствам.

Object.defineProperty

Использование

Object.defineProperty(obj, property, descriptor)
Вход в полноэкранный режим Выйти из полноэкранного режима

Существует два типа дескрипторов descriptors.

Дескрипторы данных

Name Type Default Description
value Любой допустимый тип javascript undefined Обозначает значение свойства property. По умолчанию undefined.
writeable boolean true Подразумевает, может ли значение свойства быть обновлено с помощью оператора присваивания(=).

значение

Обозначает значение свойства. По умолчанию undefined.

var myObj = Object.defineProperty({}, 'id', { value: 1 }); // value is passed
console.log(myObj); // { id: 1 }
myObj = Object.defineProperty({}, 'id', {}); // value not passed
console.log(myObj); // {id: undefined}
Войти в полноэкранный режим Выйти из полноэкранного режима

доступный для записи

Означает, может ли значение свойства быть обновлено с помощью оператора присваивания(=). По умолчанию true.

// writeable will be set to true since not passed
var myObj = Object.defineProperty({}, 'id', { value: 1 }); 
myObj.id = 10;
myObj.id; // 10

// writeable is false
myObj = Object.defineProperty({}, 'id', { value: 1, writeable: false }); 
myObj.id = 10;
myObj.id; // 1, as the value couldn't be updated
Вход в полноэкранный режим Выход из полноэкранного режима

Дескрипторы доступа

Name Type Default Description
get function undefined функция, которая возвращает значение свойства. Эта функция вызывается при обращении к свойству.
set function undefined Функция function, которая устанавливает value свойства property. Эта функция вызывается, когда значение свойства устанавливается с помощью оператора присваивания(=).

получить

Функция function возвращает value свойства. Эта функция вызывается, когда доступ к свойству осуществляется с помощью точки(.) или квадратных скобок([]).

var myObj = Object.defineProperty({}, 'id', {get: () => 10 });
myObj.id // 10
Вход в полноэкранный режим Выход из полноэкранного режима

установить

Функция function, которая устанавливает value свойства. Эта функция вызывается, когда значение свойства устанавливается с помощью оператора присваивания(=).

var myObj = Object.defineProperty({}, "id", { set: (val) => (id = val) });
myObj.id = 20;
myObj.id = 20;

myObj = Object.defineProperty({}, "id", {
  set: (val) => (id = val),
  get: () => id,
});
myObj.id = 20;
myObj.id; // 20
Вход в полноэкранный режим Выход из полноэкранного режима

Примечание: Объект может иметь либо Data Descriptors, либо Accessor Descriptors, но не оба.

myObj = Object.defineProperty({}, 'id', { value: 10, set:() => id = 10 });
// Throws error as we are using both Data and Accessor descriptors
// value is a Data descriptor whereas set is an accessor descriptor
Вход в полноэкранный режим Выход из полноэкранного режима

Дополнительные атрибуты для дескрипторов

Помимо data descriptors и accessor descriptors, существуют дополнительные атрибуты, общие для обоих дескрипторов👇🏻, которые также могут быть использованы для управления поведением.

Имя Тип По умолчанию Описание
configurable boolean false Указывает, может ли свойство быть удалено из объекта.
enumerable boolean false Подразумевает, будет ли свойство отображаться при перечислении ключей объекта.

настраиваемый

Указывает, можно ли удалить свойство из объекта. По умолчанию false.

var myObj = Object.defineProperty({}, 'id', { value: 10 });
delete myObj.id
myObj // { id: 10 } as its not configurable

myObj = Object.defineProperty({}, 'id', { value: 10, configurable: true });
delete myObj.id
myObj // {} as its configurable
Войти в полноэкранный режим Выйти из полноэкранного режима

перечисляемый

Определяет, будет ли свойство отображаться при перечислении ключей объекта, например, при использовании Object.keys или for...in. По умолчанию false.

var myObj = Object.defineProperty({}, 'id', { value: 10 });
Object.keys(myObj) // [] as the key "id" is not enumerable

myObj = Object.defineProperty({}, 'id', { value: 10, enumerable: true });
Object.keys(myObj) // ["id"] as the key "id" is enumerable
Войти в полноэкранный режим Выход из полноэкранного режима

Для обновления многочисленных свойств можно использовать Object.defineProperties.

Object.defineProperties(obj, {
  property1: descriptor,
  property2: descriptor
});
Вход в полноэкранный режим Выход из полноэкранного режима

Как упоминалось ранее, существует и третий способ создания объекта - Object.create, который помогает создать объект с указанным прототипом объекта и дескрипторами.

Теперь, когда вы знаете о дескрипторах, с помощью которых можно управлять поведением свойств, можете ли вы догадаться, почему 👇🏻 это возможно?

var myObj = { id : 10 };
myObj.id; // 10
myObj.id = 100;
myObj.id; // 100
Object.keys(id); // ["id"];
delete myObj.id
myObj; // {}
Вход в полноэкранный режим Выйти из полноэкранного режима

Это означает, что когда объекты создаются с помощью буквальной нотации / конструктора Object() или даже добавляется новое свойство с помощью оператора присваивания(.), дескрипторы устанавливаются в 👇🏻.

Имя Значение
value Значение, которое устанавливается при создании / обновлении объекта.
writeable
enumerable
configurable

Получить дескрипторы существующего объекта?

Используя дескрипторы, мы имеем гораздо больше контроля, но должен быть какой-то способ получить дескрипторы свойств существующего объекта. Да, есть статический метод getOwnPropertyDescriptor в классе Object, который помогает добиться того же 😍.

Object.getOwnPropertyDescriptor

Использование

Object.getOwnPropertyDescriptor(obj, property)
Вход в полноэкранный режим Выйти из полноэкранного режима
var myObj = { id: 10 };
Object.getOwnPropertyDescriptor(myObj, 'id')// {value: 10, writable: true, enumerable: true, configurable: true}
Войти в полноэкранный режим Выход из полноэкранного режима

Для получения дескрипторов всех свойств объекта мы можем использовать Object.getOwnPropertyDescriptors.

Object.getOwnPropertyDescriptors(obj)
Вход в полноэкранный режим Выход из полноэкранного режима

Время викторины

Пришло время провести веселую викторину 😉. Пройдите викторину здесь . Удачи!

Заключительные размышления

Если вы использовали такие методы, как Object.freeze, Object.sealed, то теперь вы знаете, что они делают за кулисами 🙂 Они изменяют дескрипторы для свойств объекта.

В большинстве случаев эти утилиты действительно помогают, но могут быть случаи, когда вы хотите получить больше контроля над свойствами, и тогда вам придется использовать эту утилиту. Надеюсь, вам понравился этот пост 😍.

Оцените статью
devanswers.ru
Добавить комментарий