Выбрать главу

let foo = {

a: "Hello",

b: "Monday";

}

Для считывания свойства нужно просто обратиться к нему напрямую:

console.log(foo.a);

Записываются же значения в свойства вполне ожидаемым способом:

foo.a = "Manic";

Помимо чтения и записи значения, мы больше ничего не можем сделать. Такова горькая правда о свойствах данных. Продолжая тему чтения и записи свойств, что, если бы мы могли следующее:

• использовать существующий синтаксис для чтения и записи значений свойств;

• получать возможность выполнять пользовательский код на фоне?

Это было бы неплохо, как считаете? Скажу больше: все это нам доступно. Такие возможности предоставляют дружественные и трудолюбивые свойства-аксессоры. В текущем разделе мы все о них узнаем и познакомимся с великими рок-звездами — загадочными геттерами и сеттерами.

Поехали!

История двух свойств

Внешне свойства-аксессоры и свойства данных очень схожи. Для свойств данных вы можете производить чтение и запись свойства:

theObj.storedValue = "Unique snowflake!"; // запись

console.log(theObj.storedValue); // чтение

С помощью свойств-аксессоров вы можете, в принципе, то же самое:

myObj.storedValue = "Also a unique snowflake!"; // запись

console.log(myObj.storedValue); // чтение

Глядя на само использование свойства, мы не можем сказать, является ли оно свойством данных или свойством-аксессором. Чтобы обнаружить отличие, нам нужно посмотреть туда, где свойство фактически определено. Взгляните на следующий код, в котором внутри объекта zorb определено несколько свойств:

let zorb = {

message: "Blah",

get greeting() {

return this.message;

},

set greeting(value) {

this.message = value;

}

};

Первое сверху — это message, стандартное свойство данных:

let zorb = {

message: "Blah",

get greeting() {

return this.message;

},

set greeting(value) {

this.message = value;

}

};

Мы узнаем, что это свойство данных, так как в нем присутствует только имя свойства и значение. А вот дальше все немного интереснее. Следующее свойство — это greeting, которое не похоже ни на одно из свойств, встреченных нами ранее:

let zorb = {

message: "Blah",

get greeting() {

return this.message;

},

set greeting(value) {

this.message = value;

}

};

Вместо того чтобы обходиться именем и значением, как message, свойство greeting разделено на две функции, которым предшествует ключевое слово get или set:

let zorb = {

message: "Blah",

get greeting() {

return this.message;

},

set greeting(value) {

this.message = value;

}

};

Эти ключевые слова и пары функций известны как геттеры и сеттеры соответственно. Особенными их делает то, что мы не обращаемся к greeting как к функции, а делаем это так же, как и с обычным свойством:

zorb.greeting = "Hola!";

console.log(zorb.greeting);

Самое же интересное происходит на уровне геттеров и сеттеров, поэтому мы рассмотрим их глубже.

Знакомство с геттерами и сеттерами

На данный момент мы знаем лишь, что геттер и сеттер — это модные названия функций, которые ведут себя как свойства. Когда мы пытаемся считать свойство-аксессор (zorb.greeting), вызывается функция геттер:

let zorb = {

message: "Blah",

get greeting() {

return this.message;

},

set greeting(value) {

this.message = value;

}

};

Аналогичным образом, когда мы задаем новое значение свойству-аксессору (zorb.greeting = "Hola!"), вызывается функция сеттер:

let zorb = {

message: "Blah",

get greeting() {

return this.message;

},

set greeting(value) {

this.message = value;

}

};

Основной потенциал геттеров и сеттеров лежит в коде, который мы можем выполнять, когда считываем или записываем свойство. Так как мы имеем дело с функциями под прикрытием, то можем выполнять любой нужный нам код. В примере с zorb мы использовали геттер и сеттер greeting, чтобы приблизительно повторить поведение свойств данных. Мы можем назначить значение, а затем считать его. Скучновато, не правда ли? Но это не должно происходить именно так, и следующие примеры привнесут больше интереса в этот процесс.

Генератор крика