Pull to refresh

Дополнение свойств в Javascript

Reading time 2 min
Views 9.4K
Предлагаю вашему вниманию перевод статьи "Advanced Javascript Properties" с сайта jstips.co.

Можно настроить объекты в javascript так, чтобы, например, установить им свойства псевдо-private или readonly. Эта функция доступна начиная с ECMAScript 5.1, поэтому поддерживается всеми браузерами последних версий. Чтобы сделать это, вам необходимо использовать метод defineProperty для Object, например так:

var a = {};
Object.defineProperty(a, 'readonly', {
  value: 15,
  writable: false
});

a.readonly = 20;
console.log(a.readonly); // 15

Синтаксис выглядит так:

Object.defineProperty(dest, propName, options)

Или для нескольких свойств:

Object.defineProperties(dest, {
  propA: optionsA,
  propB: optionsB, //...
});

Где options включает следующие атрибуты:

value — если это не getter (см. ниже), то value обязательный атрибут. {a: 12} === Object.defineProperty(obj, 'a', {value: 12})
writable — устанавливает свойство в readonly. Обратите внимание, если свойство является вложенным, то оно доступно для редактирования.
enumerable — устанавливает свойство как скрытое. Это значит, что for...of и stringify не будут в своем результате выдавать его, хотя оно по прежнему существует. Примечание. Это не значит, что свойство становится приватным. Оно все так же доступно изнутри, просто не будет выводиться.
configurable — устанавливает свойство, как не изменяемое, например защищенное от удаления или предопределения. Опять же, если свойство вложенное, то его можно редактировать.

Так что для того, чтобы создать приватное постоянное свойство, вы должны определить его как:

Object.defineProperty(obj, 'myPrivateProp', {value: val, enumerable: false, writable: false, configurable: false});

Помимо настройки свойств, defineProperty может определять их динамически, благодаря второму параметру являющемуся строкой. Например, предположим, я хочу создать свойства в соответствии с какой-либо конфигурацией:

var obj = {
  getTypeFromExternal(): true // illegal in ES5.1
}

Object.defineProperty(obj, getTypeFromExternal(), {value: true}); // ok

// For the example sake, ES6 introduced a new syntax:
var obj = {
  [getTypeFromExternal()]: true
}

Но это не все! Дополнительные свойства позволяют создавать геттеры и сеттеры, подобно другим языкам ООП. Однако в этом случае нельзя использовать writable, enumerable и configurable

function Foobar () {
  var _foo; //  true private property

  Object.defineProperty(obj, 'foo', {
    get: function () { return _foo; }
    set: function (value) { _foo = value }
  });

}

var foobar = new Foobar();
foobar.foo; // 15
foobar.foo = 20; // _foo = 20

За исключением случаев очевидного преимущества инкапсуляции и расширенных аксессоров, можно заметить, что мы не «вызываем» геттер, а получаем его как свойство, без скобок! Это восхитительно! Например, давайте представим, что у нас есть объект с кучей вложенных свойств:

var obj = {a: {b: {c: [{d: 10}, {d: 20}] } } };

Теперь, вместо a.b.c[0].d (где одно из свойств может оказаться undefined и вывалить ошибку), мы можем создать алиас:

Object.defineProperty(obj, 'firstD', {
  get: function () { return a && a.b && a.b.c && a.b.c[0] && a.b.c[0].d }
})

console.log(obj.firstD) // 10

Замечание


Если попытаться установить геттер без сеттера и попытаться задать value, вы получите ошибку. Это особенно важно при использовании вспомогательных функций, таких как $ .extend или _.merge. Будьте осторожны!

Ссылки


Tags:
Hubs:
0
Comments 5
Comments Comments 5

Articles