By Reference
###ECMASCRIPT 5 Getter/Setter
In the current standardized version of JavaScript, getter and setter functionality is available on an object property that can be used to create read-only functionality, clean up and/or restrict complex input in a setter (ie, validate data), or implement helper functionality (ie, concatenating a first+last name into a "full name" getter).
In this example, we create an object and provide a property called __skyscraper__, but only provide a __get()__ method, thereby restricting what can be done to it:
```
var buildingList = ['CN Tower', 'Garden Shed'];
var obj = {
get skyscraper() {
return buildingList[0];
}
};
```
So we can now view `obj.skyscraper` , confirming the value we expected:
```
console.log(obj.skyscraper);
>> 'CN Tower'
```
However, you can see that we are unable to alter the value of `obj.skyscraper` in a typical assignment operation:
```
obj.skyscraper = 'Starbucks Drive-Thru';
console.log(obj.skyscraper);
>> 'CN Tower'
```
By defining _only_ the getter, we've created a read-only property.
#### Getters performing more than basic value returns
Now, lets say we wanted to make our getter more robust, returning address details in addition to the building name. We can build out our getter to include data from multiple sources, returned into a single, formatted string.
```
var building = {name: 'CN Tower', location: 'Toronto, ON'};
var obj = {
get skyscraper() {
return building.name + ', ' + building.location;
}
};
console.log(obj.skyscraper);
>> 'CN Tower, Toronto, ON'
```
#### Setter
In addition to returning our property, we can provide the functionality to alter it as well.
```
var building = {name: 'CN Tower', location: 'Toronto, ON'};
var obj = {
get skyscraper() {
return building;
},
set skyscraper(val) {
building = val;
}
};
```
In this very simple form of the getter/settter functionality, we should see no difference in behavior from the way we typically view and alter properties on JavaScript objects (pre ECMA Script 5):
```
console.log(obj.skyscraper.name);
>> 'CN Tower'
obj.skyscraper = { name: 'Chase Building', location: 'Phoenix, AZ' };
console.log(obj.skyscraper.name);
>> 'Chase Building'
```
Compared to plain 'old school JavaScript:
```
var building = {name: 'CN Tower', location: 'Toronto, ON'};
var oldObject = {
skyscraper: building
};
console.log(oldObject.skyscraper.name);
>> 'CN Tower'
oldObject.skyscraper = {name: 'Sears Tower', location: 'Chicago, IL'};
console.log(oldObject.skyscraper.name);
>> 'Sears Tower'
```
Again, the same expected output from both "old school" JavaScript style and ECMA Script getters/setters.
Now, suppose we want to restrict the type of data allowed through the setter. We can implement simple or complicated validations - such as, matching against regular expressions - all with no visible impact to the assignment operations we're already used to in JavaScript.
```
var building = {name: 'CN Tower', location: 'Toronto, ON'};
var obj = {
get skyscraper() {
return building;
},
set skyscraper(val) {
var buildingNameRule = /^[0-9A-Za-z\-\._,]+/,
buildingLocationRule = /([0-9A-Za-z\-\._]+), (IA|KS|UT|VA|NC|NE|SD|AL|ID|FM|DE|AK|CT|PR|NM|MS|PW|CO|NJ|FL|MN|VI|NV|AZ|WI|ND|PA|OK|KY|RI|NH|MO|ME|VT|GA|GU|AS|NY|CA|HI|IL|TN|MA|OH|MD|MI|WY|WA|OR|MH|SC|IN|LA|MP|DC|MT|AR|WV|TX|BC|ON|NL|NS|PE|NB|QC|MB|SK|AB|NT|NU|YT{1})/;
if (typeof val === 'object' &&
typeof val.location === 'string' &&
typeof val.name === 'string' &&
buildingNameRule.test(val.name) &&
buildingLocationRule.test(val.location)) {
building = val;
}
}
};
```
Though we've added a bit more code here, essentially we're just testing that our setter is receiving an actual object with the expect string properties "name" and "location" _and_ that those properties are in the expected alphanumeric format (including valid U.S. State or Canadian province abbreviations).
So, we now use our object as we always would in JavaScript, except behind the scenes it is performing our required data validation.
```
console.log(obj.skyscraper.name)
>> 'CN Tower'
// Now, we attempt to pass in invalid values
obj.skyscraper = ['Grocery Store', 'Favorite Restaurant'];
console.log(obj.skyscraper.name)
>> 'CN Tower'
obj.skyscraper = {id: 1, state: 'AZ', name: 'my house'};
console.log(obj.skyscraper.name)
>> 'CN Tower'
obj.skyscraper = {name: 'Buckingham Palace', location: 'London, UK'};
console.log(obj.skyscraper.name)
>> 'CN Tower'
// And finally, if we pass in valid data, we verify it has been successfully set
obj.skyscraper = {name: 'Empire State Building', location: 'New York, NY'};
console.log(obj.skyscraper.name)
>> 'Empire State Building, New York, NY'
```
After we've gone to all that work to ensure data passed into our setter is properly validated, it would be unfortunate if we accidentally overwrote it with invalid data. If we roll back the ECMA Script 5 getter/setter changes and attempt to leave our object the way it was (though you could of course, still protect properties on the object by other means), we can see that's exactly the problem we run into:
```
var building = {name: 'CN Tower', location: 'Toronto, ON'};
var obj = {
skyscraper: {
get: function() {
return building;
},
set: function(val) {
var buildingNameRule = /^[0-9A-Za-z\-\._,]+/,
buildingLocationRule = /([0-9A-Za-z\-\._]+), (IA|KS|UT|VA|NC|NE|SD|AL|ID|FM|DE|AK|CT|PR|NM|MS|PW|CO|NJ|FL|MN|VI|NV|AZ|WI|ND|PA|OK|KY|RI|NH|MO|ME|VT|GA|GU|AS|NY|CA|HI|IL|TN|MA|OH|MD|MI|WY|WA|OR|MH|SC|IN|LA|MP|DC|MT|AR|WV|TX|BC|ON|NL|NS|PE|NB|QC|MB|SK|AB|NT|NU|YT{1})/;
if (typeof val === 'object' &&
typeof val.location === 'string' &&
typeof val.name === 'string' &&
buildingNameRule.test(val.name) &&
buildingLocationRule.test(val.location)) {
building = val;
}
}
}
};
```
We're trying to implement what looks like a getter/setter pattern where we're protecting the data returned by _get()_ by the complex validation rules implemented in _set()_, however because we've returned the data by-reference, we can no longer ensure the validation rules are followed properly:
```
console.log(obj.skyscraper.get().name);
>> 'CN Tower'
// Now we'll alter the properties, giving them invalid values
var refObj = obj.skyscraper.get();
refObj.name = 'House of Cards';
refObj.location = 'Neflix';
console.log(obj.skyscraper.get().name);
>> 'House of Cards'
// We can even add properties that shouldn't be there
refObj.seasons = [1,2,3];
console.log(obj.skyscraper.get().seasons);
>> [1,2,3]
```
It's certainly not a requirement for JavaScript objects to always be protected from modification, and in fact, this is often desired behavior. However, it's important to be consistent; if you need to implement complex validations in your setter, then having your getter return the "protected" object directly to the caller creates a loophole in your data validation flow. It is much like having a security guard and ticketing agent filtering every audience member who enters the gate at a concert, but then having a second gate nearby left wide-open without any monitoring in place. You can always separate your validations from the setter if you have a good use-case for returning the data by-reference, and then simply call that validator method separately whenever needed.