Modern JavaScript: Accessors in Object Literals
Welcome to the Accessors in Object Literals lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
JavaScript has always had object literals:
>
const user = {userName: 'Amir'};user.userName;Result:
'Amir'
With the object syntax above, we can only create objects with fixed properties. To change a property's value, we have to modify the object.
But a property doesn't have to hold a fixed value, like
'Amir'. It can also hold a function. To access it, we add a function call to the property, likeuser.getAge().>
const user = {getAge: function() { return 'I am ' + 22; }};user.getAge();Result:
'I am 22'
Modern JavaScript streamlines this syntax with the
getkeyword. To use it, we declare the object property as a function starting withget. When we access the property with the usualuser.agesyntax, the function is automatically called and we get its return value. This kind of property is called a "getter".>
const user = {get age() { return 38; }};user.age;Result:
Because the function above returns a fixed string, it behaves like a regular property would. But the getter function doesn't have to return a constant value. It can return anything we want.
>
const user = {get age() { return 'I am ' + 38; }};user.age;Result:
'I am 38'
Here's a code problem:
Add a
userNamegetter to this object. It should return the value of thenamevariable.let name = 'Amir';const user = {get userName() { return name; },};const userName1 = user.userName;name = 'Betty';const userName2 = user.userName;[userName1, userName2];- Goal:
['Amir', 'Betty']
- Yours:
['Amir', 'Betty']
The
getproperties above are called getters. As you might suspect, there's a complementary feature for writing to objects called setters.Normally, writing to an object's key replaces the value at that key:
>
const user = {userName: 'Amir'};user.userName = 'Betty';user.userName;Result:
'Betty'
A setter property has an associated function, like a getter does. This time the function takes one argument: the value being written to the property.
Like with getter functions, we don't need to explicitly call the setter function or manually pass in the argument. When the value of a property is modified, JavaScript calls the setter function with the new value as the argument. The setter function can do anything it wants with that argument.
>
const user = {realName: 'Amir',set userName(newName) { this.realName = newName; },};user.userName = 'Betty';user.realName;Result:
'Betty'
>
const user = {realName: 'Amir',set userName(newName) {this.realName = `New name: ${newName}`;},};user.userName = 'Betty';user.realName;Result:
'New name: Betty'
If we try to read the value of a setter, we'll get
undefined. The object has no value at that key, even though there is a setter for that key.>
const user = {realName: 'Amir',set userName(newName) { this.realName = newName; }};user.userName;Result:
undefined
We can include both a getter and a setter in one object. You can think of this as defining two parts of a single property. One part handles reading from the property value and the other part handles writing to it.
>
const user = {realName: 'Amir',get userName() { return this.realName; },set userName(newName) { this.realName = newName; },};user.userName = 'Betty';[user.realName, user.userName];Result:
['Betty', 'Betty']
We can use setters to track changes over time. Other code can modify our object properties as usual, using
user.userName = someNewName. But behind the scenes, ouruser.userNamesetter can store a history of what happened.Here's a code problem:
Add a
userNamesetter to this object. It should pushuserNameto thenameslist. Inside of the setter function, you can push a value ontonameswiththis.names.push(newName).const user = {names: ['Amir'],set userName(newName) {this.names.push(newName);}};user.userName = 'Betty';user.names;- Goal:
['Amir', 'Betty']
- Yours:
['Amir', 'Betty']
Here's a more complete example. Once again, we use an array to store the history of the user's names. The user's current
userNameis the lastuserNamein that array. We also wrap the object in acreateUserfunction so we don't have to hard-code the initialuserName.>
function createUser(userName) {return {names: [userName],get userName() { return this.names[this.names.length - 1]; },set userName(userName) { this.names.push(userName); }};}const user = createUser('Amir');user.userName = 'Betty';user.names;Result:
['Amir', 'Betty']
One more small detail. The
getandsetkeywords are required when creating getters and setters. If an object's keys are regular functions, then they won't be automatically called when we read or write to a property. We'll get the old JavaScript behavior from before getters and setters even existed.>
const user = {userName: function () { return 'Amir'; }};typeof user.userName;Result: