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, чтобы приблизительно повторить поведение свойств данных. Мы можем назначить значение, а затем считать его. Скучновато, не правда ли? Но это не должно происходить именно так, и следующие примеры привнесут больше интереса в этот процесс.
Генератор крика