ES6 Chapter 2 Syntax 2
-
5.Object Literal Extensions
-
[New Feature] Concise Properties
--------old-------- var x = 2, y = 3, o = {x: x, y: y}; --------new-------- var x = 2, y = 3, o = {x, y};
- [New Feature] Concise Methods
-
[Advantage] Concise methods are short and sweet, and nice convenience
--------old-------- var o = { x: function() {..}, y: function() {..} } --------new-------- var o = { x() {..}, y() {..} }
- [Disadvantage] Concisely Unnamed
- Concise Methods look closely. Do you see the problem?
- The concise method definition implies some thing: function(x,y) .
- Concise methods are short and sweet, and nice convenience
- [Do Not] use them to do recursion event binding/unbinding)
-
[Solution] thing: function something(..)
runSomething( { something(x,y) { if (x > y) { // equals to [ something: function(x,y) ] return something( y, x ); // ERROR will not find a something identifier } return y - x; } } );
- Concise Methods look closely. Do you see the problem?
-
[Not New Feature] ES5 Getter/Setter
var o = { __id: 10, get id() { return this.__id++; }, set id(v) { this.__id = v; } } console.log(o.id) // 10 console.log(o.id) // 11 console.log(o.id) // 12 console.log(o.__id) // 12 -- still!
-
- [New Feature] Computed Property Names
-
allows you to specify an expression, whose result is a property name
var prefix = "user_"; var o = { baz: function(..) { .. }, [ prefix + "foo" ]: function(..) { .. }, [ prefix + "bar" ]: function(..) { .. } .. };
-
a concise method or a concise generator:
var o = { ["f" + "oo"]() { .. } // computed concise method *["b" + "ar"]() { .. } // computed concise generator };
-
- [New Feature] Setting [[Prototype]]
- ES6 utility Static Function Object.setPrototypeOf(..)
-
proto is controversial
var o1 = {..}; var o2 = {..}; Object.setPrototypeOf( o2, o1 );
- [New Feature]Object super
- classless-objects-with-prototypes
-
super is only allowed in concise methods
var o1 = { foo() { console.log( "o1:foo" ); } }; var o2 = { foo() { // The super reference // be Object.getPrototypeOf(o2) -- o1.foo() super.foo(); console.log( "o2:foo" ); } }; Object.setPrototypeOf( o2, o1 ); o2.foo(); // o1:foo o2:foo
-
-
6.Template Literals (Interpolated String Literals)
- string interpolation expressions (`Hello ${name}!`) - like an IIFE, automatically evaluated inline. var name = "Kyle"; var greeting = `Hello ${name}!`; console.log( greeting ); // "Hello Kyle!" console.log( typeof greeting ); // "string" // allowed to split across multiple lines var text = `the first line the sencond line the third line!`; console.log( text ); // Now is the time for all good men // to come to the aid of their // country!
-
[New Feature]Interpolated Expressions:
function upper(s) { return s.toUpperCase(); } var who = "reader" var text = `A very ${upper( "warm" )} welcome to all of you ${upper( `${who}s` )}!`; console.log( text ); -------------------Expression Scope--------------------- // Neither the global name nor foo(..) ’s name matter. function foo(str) { var name = "foo"; console.log( str ); } function bar() { var name = "bar"; foo( `Hello from ${name}!` ); } var name = "global"; bar(); // "Hello from bar!"
-
[New Feature]Interpolated Expressions:
- It’s essentially a special kind of function call that doesn’t need the ( .. )
- The tag is a function name
-
The tag can be any expression that results in a function
function foo(strings, ...values) { console.log( strings ); console.log( values ); } var desc = "awesome"; foo`Everything is ${desc}!`; // [ "Everything is ", "!"] // [ "awesome" ] -------any expression that results in a function------- // The tag can be any expression that results in a function function bar() { return function foo(strings, ...values) { console.log( strings ); console.log( values ); } } var desc = "awesome"; bar()`Everything is ${desc}!`; // [ "Everything is ", "!"] // [ "awesome" ]
-
[Example] Practical uses
function dollabillsyall(strings, ...values) { return strings.reduce( function(s,v,idx){ if (idx > 0) { if (typeof values[idx-1] == "number") { // look, also using interpolated // string literals! s += `$${values[idx-1].toFixed( 2 )}`; } else { s += values[idx-1]; } } return s + v; }, "" ); } var amt1 = 11.99, amt2 = amt1 * 1.08, name = "Kyle"; var text = dollabillsyall `Thanks for your purchase, ${name}! Your product cost was ${amt1}, which with tax comes out to ${amt2}.` console.log( text ); // Thanks for your purchase, Kyle! Your // product cost was $11.99, which with tax // comes out to $12.95.
-
Raw Strings
function showraw(strings, ...values) { console.log( strings ); console.log( strings.raw ); } showraw`Hello\nWorld`; // [ "Hello\nWorld" ] // [ "Hello\\nWorld" ]
-
It’s important to understand the frustrations that this based programming with normal functions brings
-
7.Arrow Functions
-
[anonymous function expressions] no named reference for recursion or event binding/unbinding
var f1 = () => 12; var f2 = x => x * 2; // like: a = a.map( v => v * 2 ); var f3 = (x,y) => { var z = x * 2 + y; y++; x *= 3; return (x + y + z) / 2; };
- short single statement utilities
- arrow functions is an attractive and lightweight alternative to the more verbose function keyword and syntax.
-
[Inversely proportional]readability gains: The longer the function, the less => helps; the shorter the function, the more => can shine.
var a = [1,2,3,4,5]; a = a.map( v => v * 2 ); console.log( a ); // [2,4,6,8,10]
- [sensible and reasonable] adopt => to replace short inline function expressions
-
[New Feature] => is syntactic stand-in for “var self = this” or “bind(this)”
var controller = { makeRequest: function() { var body = document.getElementById("body"); body.addEventListener( "click", () => {this.helper();}, false ); }, helper: function(){ alert('test'); } }; controller.makeRequest();
-
[Not] quite so simple: use => with a this -aware function
var controller = { makeRequest: (..) => { this.helper(..); }, helper: (..) => { } }; // global scope: this points to the global object. controller.makeRequest(..);
-
- [Conclusion]
- using Arrow function when
- 1.short, single-statement inline function expression returns some computed value, doesn’t already make a this reference inside it, no self-reference(recursion, event binding/unbinding)
- 2.inner function expression which relying on a “var self = this” or “.bind(this)”, call on it in the enclosing function.
- 3.make a lexical copy of arguments:like an inner function expression that’s relying on “var args = Array.prototype.slice.call(arguments)”
- Avoid Arrow function syntax.
-
For everything else — normal function declarations, longer multi-statment function expressions, functions which need a lexical name identifier self-reference(recursion, etc.), and any other function which doesn’t fit the previous characteristics — you should probably avoid => function syntax.
// Array-like objects / collections // The arguments inside a function is an example of an 'array-like object'. var a={length:2,0:'first',1:'second'}; Array.prototype.slice.call(a);// ["first", "second"] function list() { return Array.prototype.slice.call(arguments); } var list1 = list(1, 2, 3); // [1, 2, 3]
-
- using Arrow function when
-
-
8.for..of Loops
- [New Feature] for..of Loops
- 1.for..of VS. for..in
- for..of loops over the values
-
for..in loops over the keys/indexes
var a = ["a","b","c","d","e"]; for (var idx in a) { console.log( idx ); // 0 1 2 3 4 } for (var val of a) { console.log( val ); // "a" "b" "c" "d" "e" } ---------manually iterating an iterator-------- var a = ["a","b","c","d","e"]; for (var val, ret, it = a[Symbol.iterator](); !(ret = it.next()) && !ret.done; ) { val = ret.value; console.log( val ); // "a" "b" "c" "d" "e" }
- 2.Standard built-in values include default iterables
-
arrays, strings, generators, collections / TypedArrays
for (var c of "hello") { console.log( c ); // "h" "e" "l" "l" "o" } ------------------------------------------------------ var o = {}; for (o.a of [1,2,3]) { console.log( o.a ); // 1 2 3 } for ({x: o.a} of [ {x: 1}, {x: 2}, {x: 3} ]) { console.log( o.a ); // 1 2 3 }
-
- 3.for..of loops can be prematurely stopped
- break , continue , return (if in a function), and thrown exceptions
- 1.for..of VS. for..in
- [New Feature] for..of Loops
-
9.Regular Expressions
- 1.Unicode Flag (//u)
- as of ES6, the u flag tells a regular expression to process a string with the intepretation of Unicode (UTF-16) characters
- JavaScript strings are typically interpreted as sequences of 16-bit characters
-
correspond to Basic Multilingual Plane BMP
"UTF-16" doesn’t strictly mean 16 bits. Modern Unicode uses 21 bits,
- [Example] the musical symbol G-clef(U+1D11E)
- 𝄞 (G-clef)
-
two separate characters (0xD834 and 0xDD1E)
/𝄞/.test( "𝄞-clef" ); // true /^.-clef/ .test( "𝄞-clef" ); // false: the match fails (2 charac‐ters) /^.-clef/u.test( "𝄞-clef" ); // true
- 2.Sticky Flag (//y)
-
a virtual anchor
var re1 = /foo/, str = "++foo++"; re1.lastIndex; // 0 re1.test( str ); // true re1.lastIndex; // 0 -- not updated re1.lastIndex = 4; re1.test( str ); // true -- ignored `lastIndex` re1.lastIndex; // 4 -- not updated
-
Three things:
- (1) test(..) ignore the lastIndex ’s value, performs its match from the beginning;
- (2) does not have a ^ start-of-input anchor, free to move ahead to look for a match.
- (3) lastIndex is not updated by test(..)
-
- 2.Regular Expression flags
-
Ironically, Prior to ES6, see what flags the regular expression had applied
var re = /foo/ig; re.toString(); // "/foo/ig" var flags = re.toString().match( /\/([gim]*)$/ )[1]; flags; // "ig"
-
As of ES6,
var re = /foo/ig; re1.source; // "foo" re.flags; // "gi"
-
- 1.Unicode Flag (//u)
-
10.Number Literal Extensions
-
Here are the new ES6 number literal forms:
var dec = 42, oct = 0o52, // or '0O52' hex = 0x2a, // or '0X2a' bin = 0b101010; // or '0B101010' var a = 42; a.toString(); // "42" -- also `a.toString( 10 )` a.toString( 8 ); // "52" a.toString( 16 ); // "2a" a.toString( 2 ); // "101010"
-
-
11.Unicode
- Basic Multilingual Plane (BMP): The Unicode characters that range from 0x0000 to 0xFFFF
- Extended Unicode characters: range up to 0x10FFFF
-
prior to ES6, using a surrogate pair
//surrogate pair var gclef = "\uD834\uDD1E"; console.log( gclef ); // " 𝄞 "
-
As of ES6, Unicode code point escaping
var gclef = "\u{1D11E}"; console.log( gclef ); // " 𝄞 "
-
Unicode-Aware String Operations
var snowman = "☃"; snowman.length; // 1 var gclef = "𝄞"; gclef.length; // 2 var gclef = "𝄞"; [...gclef].length; // 1 Array.from( gclef ).length; // 1 gclef.normalize().length; // 1
-
Character Positioning
// prior to ES6 s1.charAt(2) // as of ES6 [...s1.normalize()][2]; s1.normalize().codePointAt( 2 ).toString( 16 ); String.fromCodePoint( 0x107 ); // "ć" String.fromCodePoint( s1.normalize().codePointAt( 2 ) );
- Unicode Identifier Names
-
rare and academic
var \u03A9 = 42; // same as: var Ω = 42;
-
-
11.Symbols (unique string value)
- Don’t have a literal form
- create a symbol:
- not use new with Symbol(..)
- The parameter passed to Symbol(..) is optional
-
The typeof output is a new value ( “symbol” ) that is the primary way to identify a symbol.
var sym = Symbol( "some optional description" ); typeof sym; // "symbol"
-
construct a boxed wrapper object form of a symbol value
sym instanceof Symbol; // false var symObj = Object( sym ); symObj instanceof Symbol; // true symObj.valueOf() === sym; // true
- think of this symbol value as an automatically generated, unique (within your application) string value
- [Q] if the value is hidden and unobtainable, what’s the point of having a symbol at all?
-
(1)to create a string-like value that can’t collide with any other value
// EVT_LOGIN holds a value that cannot be duplicated const EVT_LOGIN = Symbol( "event.login" );
-
(2)to create a special property that is hidden or meta in usage
-
A typical usage: Singleton Pattern
---------------------Singleton----------------------- const INSTANCE = Symbol( "instance" ); function HappyFace() { if (HappyFace[INSTANCE]) return HappyFace[INSTANCE]; function smile() { .. } return HappyFace[INSTANCE] = { smile: smile }; } var me = HappyFace(), you = HappyFace(); me === you;
-
-
- [Q] if the value is hidden and unobtainable, what’s the point of having a symbol at all?
- Symbol Registry
-
create symbol values with the global symbol registry
const EVT_LOGIN = Symbol.for( "event.login" ); ---------------------Singleton----------------------- function HappyFace() { const INSTANCE = Symbol.for( "instance" ); if (HappyFace[INSTANCE]) return HappyFace[INSTANCE]; // .. return HappyFace[INSTANCE] = { .. }; }
-
- Symbols as Object Properties
- a property symbol is not actually hidden or inaccessible
-
Object.getOwnPropertySymbols(..)
var o = { foo: 42, [ Symbol( "bar" ) ]: "hello world", baz: true }; Object.getOwnPropertyNames( o ); // [ "foo","baz" ] Object.getOwnPropertySymbols( o ); // [ Symbol(bar) ] -------------------Built-in Symbols------------------------- var a = [1,2,3]; a[Symbol.iterator]; // native function