ES6
1. Online Test Tools
2. Notes
2.1. 1. Function parameters' default values
避免沒有傳參數給 function 導致 expection 的方法是設定參數預設值。
ES5:
// primitive paramters
function myFunc1(n) {
n = n === undefined ? 123 : n;
console.log(n);
}
myFunc1();
// object paramters
function myFunc2(person) {
person = person === undefined ? {} : person;
var name = person.name === undefined ? 'John' : person.name;
var age = person.age === undefined ? 20 : person.age;
var weapon = person.weapon === undefined ? {name: 'sword', attack: 99} : person.weapon;
console.log(name, age, weapon); //Rubio 20 {name: "sword", attack: 99}
}
myFunc2({name: 'Rubio'});
ES6:
// primitive paramters
function myFunc1(n = 123){
console.log(n);
}
myFunc1();
// object paramters
function myFunc2({name='John', age=20, weapon={name: 'sword', attack: 99}}) {
console.log(name, age, weapon); //Rubio 20 {name: "sword", attack: 99}
}
myFunc2({name: 'Rubio'});
Note: ES6 的參數預設值只會判斷是不是 undefined。 如果是 null 或其他想檢查的情境,仍需自己判斷。
2.2. 2. Template Literals
允許將字串實字模板化,嵌入 JS 變數或語法。
var x = "hello";
// ES5
console.log("x=[" + x + "]");
console.log("x=[" + (123+456) + "]");
// ES6
console.log(`x=[${x}]`);
console.log(`x=[${(123+456)}]`);
2.3. 3. Multi-line Strings
//ES5
var str = 'line1'
+'line2';
//ES6
var str = `line1
line2`;
mynote: 偏向還是用 ES5 的寫法,避免預期外的奇怪問題。 因為根據多個 online tool 測試轉譯結果,似乎換行會多出
\n
符號,而且會被受縮排的空白影響。
// ES6
var str = `line1
line2`;
// Convet to ES5
var str = 'line1\n line2';
2.4. 4. Destructuring Assignment
解構賦值,可以用用簡便的語法,取出陣列或 object 裡對應位置的值。
Array destructuring
1. Basic assignment and assigning the rest
var [a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20
var [a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]
var ary = ['apple', 'banana', 'car', 'dog'];
[a, b, ...rest] = ary;
console.log(a); // 'apple'
console.log(b); // 'banana'
console.log(rest); // ['car', 'dog']
2. Ignoring some values
可選擇性擷取或跳過
var [a, b] = [1, 2, 3, 4];
console.log(a); // 1
console.log(b); // 2
var [a, , b] = [1, 2, 3, 4];
console.log(a); // 1
console.log(b); // 3
var [a, , , b] = [1, 2, 3, 4];
console.log(a); // 1
console.log(b); // 4
var [, , , , ,] = [1, 2, 3, 4]; // ignore all
3. Default values
當對應的元素是 undefined 時會使用預設值
var [a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7
4. Swapping variables
不用再設額外變數去暫存
var a = 1;
var b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
5. Parsing an array returned from a function
function f() {
return [1, 2];
}
var [a, b] = f();
console.log(a); // 1
console.log(b); // 2
var url = 'https://developer.mozilla.org/en-US/Web/JavaScript';
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]
var [, protocol, fullhost, fullpath] = parsedURL;
console.log(protocol); // "https"
Object destructuring
1. Basic assignment and Assigning to new variable names
冒號前面是原 key 值,後面是新宣告的變數名
var { name: n, age: a } = { name: 'John', age: 20 };
console.log(n); // 'John'
console.log(a); // 20
var { name: name, age: age } = { name: 'John', age: 20 };
console.log(name); // 'John'
console.log(age); // 20
var { name, age } = { name: 'John', age: 20 };
console.log(name); // 'John'
console.log(age); // 20
({ name, age } = { name: 'Rubio', age: 18 }); // Note: For this syntax `(` and `)` is necessary, or SyntaxError
console.log(name); // 'Rubio'
console.log(age); // 18
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
console.log(a); // 10
console.log(b); // 20
console.log(rest); // { c: 30, d: 40 }
2. Default values
當對應的元素是 undefined 時會使用預設值
var { name='John', age=20 } = { name: 'Rubio' };
console.log(name); // 'Rubio'
console.log(age); // 20
var { name: n = 'John', age: a = 20 } = { name: 'Rubio' };
console.log(n); // 'Rubio'
console.log(a); // 20
3. Nested object and array destructuring
巢狀物件或陣列的解構
var person = {
name: 'John',
weapon: {
name: 'Sword',
attack: 99
},
items:[
{ name: 'Herb', price: 5},
{ name: 'Ruby', price: 20000},
]
};
var {name: hero, weapon: { attack: atk }, items: [, {name: present}] } = person;
console.log(hero); // 'John'
console.log(atk); // 99
console.log(present); // 'Ruby'
4. For of iteration and destructuring
循環解構
var heroes = [
{
name: 'John',
weapon: {
name: 'Sword',
attack: 99
},
},
{
name: 'Arthur',
weapon: {
name: 'Bow',
attack: 70
},
}
];
for (var {name: n, weapon: {attack: atk}} of heroes) {
console.log('Name: ' + n + ', Attack: ' + atk);
}
// =========== Result:
// Name: John, Attack: 99
// Name: Arthur, Attack: 70
5. 應用: 從函式參數的物件中快速提出某屬性的值
function atkValue({weapon: {attack: atk}}) {
return atk;
}
var person = {
name: 'John',
weapon: {
name: 'Sword',
attack: 99
},
};
console.log('Attack Value:: ' + atkValue(person)); // "Attack Value:: 99"
6. Computed object property names and destructuring
以物件演算屬性名稱解構 (物件演算屬性名稱指——母物件["子物件名稱"]——的表示方式)
let key = 'name';
var {[key]: n} = { name: 'John' };
console.log(n); // 'John'
7. Invalid JavaScript identifier as a property name
利用解構的寫法取得不合格的 JS 識別名稱
const foo = { 'fizz-buzz': true };
const { 'fizz-buzz': fizzBuzz } = foo;
console.log(fizzBuzz); // "true"
2.5. 5. Object Literals
提供 Object 定義的縮寫語法
function getHero(name, weapon, career) {
return {
// property value shorthand syntax
name, // same as name: name
weapon,
// computed values now work with object literals
['be' + career]: true,
// Method definition shorthand syntax omits `function` keyword & colon
// Note: 這樣寫的效果會是 regular function,而非 arrow function
doAttack() {
console.log(`Use ${weapon.name}! HP -${weapon.attack}`);
}
};
}
let hero = getHero('John', {name: 'Sword', attack: 99}, "Warrior");
console.log(hero);
hero.doAttack(); // "Use Sword! HP -99"
2.6. 6. Arrow Functions
Intro:
- Arrow function expression,或稱 fat arrow function,最初在 coffeescript 的語法中流行。
- Arrow function 不是單純語法簡化而已,也會對 function 實際運作多了些限制或改變。
Usage Note:
- Arrow functions must be defined before they are used.
- Using
const
is safer than usingvar
, because a function expression is a constant value. - 原則上似乎可以避免使用
function
關鍵字去宣告,如果在物件裡需要用到 Regular function 的效果,可用 Object literals 寫法 (但還是要視乎使用情境)
Syxtax Examples:
// basic arrow function expression
var myFunc = (n1 ,n2) => {
return n1 + n2;
};
// if only a return statement, omit return and {}
var myFunc = (n1, n2) => n1 + n2;
// if only one parameter, () can be omitted
var myFunc = x => { console.log(x) };
// if no parameter, () is necessary
var myFunc = () => { console.log(123) };
About arguments
arguments
object - no longer bound with arrow function
不能使用 arguments,讓 function 使用上更嚴謹。
const getSum = function (n1, n2, n3) {
console.log(arguments); // [100, 200, 300]
return n1 + n2 + n3;
};
console.log( getSum(100, 200, 300) ); //600
const getSumArrow = (n1, n2, n3) => {
//console.log(arguments); // it will occur ReferenceError: arguments is not defined
return n1 + n2 + n3;
};
console.log( getSumArrow(100, 200, 300) ); //600
About this
this
keyword - no longer bound
對 this
的效果會有影響,根據 obj.method()
判斷當前 this
是誰的公式在 arrow function 不適用。
如果用的是 arrow function,不會再產生一個 this
引用物件,當前 this
會是上一個 this
物件。
Example 1: With Regular function
const hero = {
name: 'Soar',
weapons: ['Sword', 'Bow', 'Axe'],
printArmedWeapon: function(){
const me = this;
this.weapons.forEach(function(el){
console.log(`Hero ${me.name} got weapon ${el}`); // here, `this` means `hero.weapons`, instead of `hero`
});
}
};
hero.printArmedWeapon();
// Result:
// Hero Soar got weapon Sword
// Hero Soar got weapon Bow
// Hero Soar got weapon Axe
Example 2: With Arrow function
const hero = {
name: 'Soar',
weapons: ['Sword', 'Bow', 'Axe'],
printArmedWeapon: function(){ // arrow function
this.weapons.forEach((el) => {
console.log(`Hero ${this.name} got weapon ${el}`); // `this` not bound the `forEach()`
});
}
};
hero.printArmedWeapon();
// Result:
// Hero Soar got weapon Sword
// Hero Soar got weapon Bow
// Hero Soar got weapon Axe
Example 3: With Arrow function further
const hero = {
name: 'Soar',
weapons: ['Sword', 'Bow', 'Axe'],
printArmedWeapon: () => { // arrow function
this.weapons.forEach((el) => {
console.log(`Hero ${this.name} got weapon ${el}`);
});
}
};
hero.printArmedWeapon();
// TypeError: Cannot read property 'forEach' of undefined
Example 4: With Object literals
是 regaular function 的效果
const hero = {
name: 'Soar',
weapons: ['Sword', 'Bow', 'Axe'],
printArmedWeapon() { // Object literals
this.weapons.forEach((el) => {
console.log(`Hero ${this.name} got weapon ${el}`);
});
}
};
hero.printArmedWeapon();
// Result:
// Hero Soar got weapon Sword
// Hero Soar got weapon Bow
// Hero Soar got weapon Axe
Example 5: Another Example
const multyplier = {
numbers: [2, 3, 4],
//multiplyBy(){ return 2},
multiplyBy: () => 2,
multiply(){
return this.numbers.map(x => x * this.multiplyBy());
}
}
console.log( multyplier.multiply() ); //[4,6,8]
2.7. 7. Promises
Promise.all
把許多promise的函式組成一個Array放入Promise.all內,當裡面每個都resolve或其中一個被reject時才會執行後面的then方法
Promise.all([promises...])
.then(function (posts) {
// ...
}).catch(function(reason){
// ...
});
2.8. 8. Let & Const, Block-Scoped
Intro
let
只會在目前的 { } 內有效,而且同一個 block 內不能重覆定義(即使另一個是用var
),會 throw Error 提示- 但一個 block 內的小 block 允許再定義同名的變數
const
同let
一樣 (只會在目前的 { } 內有效 + 不能重複定義),另外多了:- 定義時必須 initialize
- 後續不能更改
- 應避免使用
var
,改用const
和let
let
{
var x = 10;
var x = 2;
}
console.log(x); // 2
var x = 10;
{
let x = 2;
}
console.log(x); // 10
let x = 10;
{
let x = 2;
}
console.log(x); // 10
{
let x = 10;
}
console.log(x); // ReferenceError: x is not defined
{
var x = 10;
let x = 2; // SyntaxError: Identifier 'x' has already been declared
}
console.log(x);
const
const x; // SyntaxError: Missing initializer in const declaration
const x = 10;
const x = 10; // SyntaxError: Identifier 'x' has already been declared
const x = 10;
x = 20; // TypeError: Assignment to constant variable.
{
const x = 10;
}
console.log(x); // ReferenceError: x is not defined
Block Level Scope
- Function scope 也是一種比較大的 Block scope
- 一份檔案算一種更大的 Block scope,但不等於 Global scope (In HTML, the global scope is the window object)
var
vslet
vsconst
var
可以當 function scope/global scopelet
&const
可以是 block scope/function scope,無法用作 global scope (無法在 function 內用this
或window
呼叫)
let n4 = "Soar";
myFunc3();
function myFunc3(){
console.log("myFunc3(): typeof n4=", typeof n4, " value=", n4);
console.log("myFunc3(): typeof this.n4=", typeof this.n4, " value=", this.n4);
console.log("myFunc3(): typeof window.n4=", typeof window.n4, " value=", window.n4);
}
// Result:
// myFunc3(): typeof n4= string value= Soar
// myFunc3(): typeof this.n4= undefined value= undefined
// myFunc3(): typeof window.n4= undefined value= undefined
2.9. 9. Classes
Intro
運用 prototype 和 function 實用出類似具有 inheritance 結構的的類別(和傳統 java, python 的類別有差別)
Simple Example:
class Drink {
constructor(name = 'water', price = 1) {
this.name = name;
this.price = price;
}
generateTag() {
console.log(this.toString());
}
toString(){
return `${this.name}, Price is ${this.price}`;
}
}
class RedTea extends Drink {
constructor(){
super('RedTea', 35);
}
generateTag() {
super.generateTag();
console.log('Thank you!');
}
}
let drink1 = new RedTea();
drink1.generateTag();
console.log(drink1); // will print with object format, instead of calling toString()
console.log(drink1.toString());
console.log('' + drink1); // // will call toString()
let drink2 = new Drink();
drink2.generateTag();
console.log(drink2);
// "RedTea, Price is 35"
// "Thank you!"
// RedTea {name: "RedTea", price: 35}
// "RedTea, Price is 35"
// "RedTea, Price is 35"
// "water, Price is 1"
// Drink {name: "water", price: 1}
2.10. 10. Module
模組化是 Node.js 中最重要的觀念之一,這個觀念讓大規模的 JavaScript 系統成為可能,模組化程設在 JS 流行也是基於此。
Node.js 使用的
require()
是屬於 CommonJS 體系,但在 ES6 不用require
,而使用import
(兩者亦可混合使用)。在 ES6 出來前,Node.js 或瀏覽器端有各家套件,遵循各自的 module 實作規範
- Node 遵循 CommonJS (
require
只是 Node.js 的一個 private global function;module.exports
也只是 Node.js 的一個 private global variable) - requirejs 遵循 AMD
- seajs 遵循 CMD
- Node 遵循 CommonJS (
Node.js 現階段不支援
import
&export
,需要通過 babel 進行轉譯成 Node.js 的模組化語法。- Test with Node.js v10.6.0 -> SyntaxError: Unexpected token export
Export
export
要放在 function 外不然會出錯
Syntax 1: 基本寫法
export var port = 3000
export var person = 'John';
export function add(n1, n2) {
return n1+n2;
}
Syntax 2: 可最後一次 export (建議)
var port = 3000
var person = 'John';
export {port, person};
Syntax 3: 可用 `as 改變 import 時的名稱
export {port as p, person as heor};
Import
也可一次載入
import {port, person} from './config.js'
console.log(port) // 3000
Syntax 2: 可一次 import
import * as config from './config.js'
Syntax 3: 可用 as
改變 import 後的名稱
import {port as p, person as hero} from './config.js'
Export Default
前面的 export 寫法在 import 時,需要知道該變數名稱才可引用。
為了解決此問題,可使用 export default
a.js
export default function () {
console.log('I'm banana');
}
b.js
import customName from './a.js';//可自行指定名稱
customName(); // 'I'm banana'
在 React 通常會如下運用:
// Component1.js
export default class { ... }
// main.js
import Component1 from './Component1.js'
2.11. 11. spread syntax (展開運算子)
var numbers = [1, 2, 3, 4];
Math.max(...numbers) // 4
Math.min(...numbers) // 1
function myFunc(x, y, z) { console.log(y) }
var args = [0, 1, 2];
myFunc(...args); // same as myFunc(0,1,2)
var ary = ["hello", 123, ...args, "go"];
console.log(ary); // ["hello", 123, 0, 1, 2, "go"]
2.12. 12. Generator
功能:也是用來處理異步函式,讓他順序執行 不一樣的地方在於function後的星號,和yield
function* Fruit() {
yield 'apple';
yield 'banana';
return 'ending';
}
var a = Fruit();
之後輸入a.next();
3. Reference
- [ES6] Javascript 開發者必須知道的 10 個新功能
- 翻譯有誤?? 它沒有自己的 this
- Arrow functions do not have their own this. (https://www.w3schools.com/js/js_es6.asp)
- 解構賦值- JavaScript | MDN
- ECMAScript 6 - JavaScript 6 - W3Schools
- ES6,ES7,ES8 · class - easonwang01 - GitBook
- Node中没搞明白require和import,你会被坑的很惨