This article is a continuation of last week’s post on ES2017 Async-Await, detailing the updates of ES2017.
Check out the ES2016 plus compatibility table for more information on the current browser support. Most likely, you will need a transpiler.
Use the ES2017 Babel Preset for code transpilation if you want to support older browsers.
New Object Extensions
In this section, we will introduce three Object
methods:
Object.entries
,
Object.values
,
Object.getOwnPropertyDescriptors
.
Object.entries and Object.values
We already know Object.keys
:
let account = {
first: 'Zsolt',
last: 'Nagy',
email: '[email protected]'
};
Object.keys( account );
> ["first", "last", "email"]
In ES7, Object.values
and Object.entries
are also available:
Object.values( account )
> ["Zsolt", "Nagy", "[email protected]"]
Object.entries( account )
> [ ["first", "Zsolt"],
["last", "Nagy"],
["email", "[email protected]"] ]
Object.entries
can also be used for creating maps.
let accountMap = new Map( Object.entries( account ) );
> Map {
"first" => "Zsolt",
"last" => "Nagy",
"email" => "[email protected]"
}
Symbol keys are ignored from the keys, values, and entries arrays.
The entries
method was already defined for arrays in ES6, and it returned an ArrayIterator
.
let iterator = Object.values( account ).entries();
> ArrayIterator {}
console.log( iterator.next() );
> { value: [0, "Zsolt"], done: false }
for ( let [val, key] of iterator ) {
console.log( val, key );
}
> 1 "Nagy"
> 2 "[email protected]"
Object.getOwnPropertyDescriptors
Object.getOwnPropertyDescriptors
returns all property descriptors of its first argument:
let player = {
cards: [ 'Ah', 'Qc' ],
chips: 1000
};
let descriptors =
Object.getOwnPropertyDescriptors( player );
console.log( descriptors );
> Object {cards: Object, chips: Object}
console.log( descriptors.cards );
> Object {
value: Array[2],
writable: true,
enumerable: true,
configurable: true
}
Object.getOwnPropertyDescriptors
returns all property descriptors in an object with the same keys as the keys of the original object. The following four property descriptors are returned (source: developer.mozilla.com):
value
: the value of the property
writable
: true
if and only if the value associated with the property may be changed (data descriptors only)
get
: A function which serves as a getter for the property, or undefined if there is no getter (accessor descriptors only)
set
: A function which serves as a setter for the property, or undefined if there is no setter (accessor descriptors only)
configurable
: true
if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object
enumerable
: true
if and only if this property shows up during enumeration of the properties on the corresponding object
Let’s construct an example for getters and setters
let player = {
cards: [ 'Ah', 'Qc' ],
chips: 1000,
flop: [ '7d', '7c', '2c' ],
get hand() {
return [ ...this.cards, ...this.flop ];
},
set hand( newHand ) {
if ( newHand.length && newHand.length === 5 ) {
[ this.cards[0],
this.cards[1],
...this.flop
] = newHand;
}
}
};
let descriptors =
Object.getOwnPropertyDescriptors( player );
console.log( descriptors );
> Object {
cards: Object,
chips: Object,
flop: Object,
hand: Object
}
console.log( Object.keys( descriptors.hand ) );
> ["get", "set", "enumerable", "configurable"]
descriptors.hand.get
> function get hand() {
return [ ...this.cards, ...this.flop ];
}
Object.getOwnPropertyDescriptors
handles String keys as well as Symbol keys[nodejssymbolshow]:
[nodejssymbolshow]: in order to show Symbol keys in node and in some browsers, instead of console.log
, use console.dir
with the flag showHidden: true
. Check out this node issue for more information, or re-read the (relevant section) of Chapter 9.
let s = Symbol('test');
let test = {
[s]: 'test'
};
console.log( Object.getOwnPropertyDescriptors( test ) );
> { Symbol(test): Object {
configurable : true
enumerable : true
value : "test"
writable : true
}
}
As a consequence, Object.getOwnPropertyDescriptors
can be used to make shallow copies of objects using Object.create
.
Object.create
takes two arguments:
- the prototype of the object we wish to clone,
- the property descriptors of the object.
In order to illustrate the difference between a shallow copy and a deep copy, let’s create a shallow copy of the player
object defined above.
let player = {
cards: [ 'Ah', 'Qc' ],
chips: 1000,
flop: [ '7d', '7c', '2c' ],
get hand() {
return [ ...this.cards, ...this.flop ];
},
set hand( newHand ) {
if ( newHand.length && newHand.length === 5 ) {
[ this.cards[0],
this.cards[1],
...this.flop
] = newHand;
}
}
};
let proto = Object.getPrototypeOf( player );
let descriptors =
Object.getOwnPropertyDescriptors( player );
let newPlayer = Object.create( proto, descriptors );
newPlayer.chips = 1500;
console.log( player.chips, newPlayer.chips );
> 1000 1500
We have created two seemingly independent entities. However, when trying to change a card of the new player, the change will be made in the context of the old player as well.
newPlayer.cards[1] = 'Ad';
console.log( newPlayer.cards[1], player.cards[1] );
> 'Ad' 'Ad'
This is because shallow copying only copied the reference of the cards array to the new player object. The original and the copied reference point at the exact same array.
New String Extensions
This section is about two String prototype extensions:
These two methods are not yet implemented in all browsers. You need to open the Firefox developer tools or Chrome 57 to experiment with them.
Padding is used to add additional characters to the start or the end of a string so that it reaches a given size.
Padding is useful in character mode for alignment.
In the following example, let’s format the amounts such that the integer part contains 6 characters, and the fractional part contains 2 characters. Let’s pad the characters in front of the interger part with spaces, and the decimal part with zeros.
Let’s console log the result.
let amounts = [
'1234.0',
'1',
'2.56'
];
console.log( `|dddddd.ff|` );
for ( let amount of amounts ) {
let [ front, back = '' ] = amount.split('.');
front = front.padStart( 6 );
back = back.padEnd( 2, '0' );
console.log( `|${front}.${back}|` );
}
> |dddddd.ff|
> | 1234.00|
> | 1.00|
> | 2.56|
If the second argument of padStart
or padEnd
is not given, ' '
characters will be used by default.
If you are interested in similar articles, sign up for weekly email updates below:
Learn ES6 in Practice
Sign up below to access an ES6 course with many exercises and reference solutions.