![](/blog/2019/12/28/ES6/ES6.jpg)
關於ES6新增的語法
- 讓原有的 JS 語法撰寫更為精簡 (語法糖)
- 讓 JS 撰寫觀念更為直覺、簡便 (新方法)
變數
var
宣告變數是定義了一個全域變數,或是在整個 function 而不管該區塊範圍。函式作用域(function scope)。
var
可以重複宣告,後宣告的值會取代前宣告的。- 有提升(Hoisting)的特性。
let
let
: 可以宣告只能在目前區塊、階段或表達式中作用的變數。
- 作用範圍是它們被定義的區塊,以及該區塊包含的子區塊。
區塊作用域(block scope)
{}
。 - 無法重複宣告
- 有暫時性死區(TDZ) (TDZ 與 Hoisting 不同)
- 一樣會有創造階段。
- 但從創造階段到實際宣告會出現 TDZ ,這個區域無法呼叫變數。
- 有創造到執行的概念,但不會預先出現 undefined ,而是會出現錯誤提示。
const
const
: Constants (常數) ,具有區塊可視範圍。常數不能重複指定值,也不能重複宣告。
- 作用範圍是它們被定義的區塊,以及該區塊包含的子區塊。
區塊作用域(block scope)
{}
。 - 不可再指定(can’t re-assignment)。無法使用賦值運算子再次賦予值給此變數。
但如果宣告的常數是一個物件或陣列類型,像這種參照類型的值,裡面的值是可以作改變的。
- 有暫時性死區(同
let
)。
字串
舊有組字串的方式是使用引號 '
"
& 運算子 +
來組合,可讀性不佳。
Template literals
- 將所有字串以反引號
`
包覆。 - 變數則使用
${}
來進行插入。 - 因換行符號是 Template literals 的一部份,以反引號
`
包覆多行字串,可達到多行字串的效果。 ${}
內也可以使用 javascript 方法。
函式
箭頭函式簡介
- JS函式表達式
const callName = function(someOne) { |
- 箭頭函式
將function
移除,並於()
後方加入=>
const callName = (someOne) => { |
- 如果程式碼為表達式可以縮寫
- 當箭頭函式裡的內容只有單行的時候,我們可以拿掉
return
和外面的大括號{}
,會自動 return 。const callName = (someOne) => '我是 ' + someOne;
console.log(callName(某某)) - 如果輸入的參數只有一個,我們可以移除掉外面的括號
const callName = someOne => '我是 ' + someOn;
console.log(callName(某某)) //我是 某某 - 沒有傳入參數的情況下,
()
不可省略。const callName = () => '我是 ' + '某某'
console.log(callName()) //我是 某某
- 當箭頭函式裡的內容只有單行的時候,我們可以拿掉
與傳統函式不同之處
沒有 arguments 參數
- 原始寫法
const num = function() {
console.log(arguments)
}
console.log(num(1,2,3,4,50,60,70,90,100))
//Arguments(9) [1, 2, 3, 4, 50, 60, 70, 90, 100, callee: ƒ, Symbol(Symbol.iterator): ƒ] - 箭頭函式,使用
arguments
會出現錯誤const num = () => {
console.log(arguments)
}
console.log(num(1,2,3,4,50,60,70,90,100)) //arguments is not defined - 可以使用 其餘參數 解決此問題
const num = (...arg) => {
console.log(arg)
}
console.log(num(1,2,3,4,50,60,70,90,100)) //[1, 2, 3, 4, 50, 60, 70, 90, 100]
this 綁定的差異
- 原始寫法
var name = "全域"
const local = {
name: "區域",
callName : function() {
console.log('1.', this.name);
setTimeout(function () {
console.log('2.', this.name)
console.log('3.', this)
}, 10)
}
}
local.callName() - 箭頭函式,沒有自己的
this
setTimeout
改成箭頭函式var name = "全域"
const local = {
name: "區域",
callName : function() {
console.log('1.', this.name);
setTimeout(() => {
console.log('2.', this.name)
console.log('3.', this)
}, 10)
}
}
local.callName()- 物件內的
function
改成箭頭函式var name = "全域"
const local = {
name: "區域",
callName : () => {
console.log('1.', this.name);
setTimeout(() => {
console.log('2.', this.name)
console.log('3.', this)
}, 10)
}
}
local.callName() const vm = this
var name = "全域"
const local = {
name: "區域",
callName () {
const vm = this
console.log('1.', vm.name);
setTimeout(() => {
console.log('2.', vm.name)
console.log('3.', vm)
}, 10)
}
}
local.callName()
DOM 指向的 this 也不同
因 箭頭函式,沒有自己的 this
,所以 this
指向全域 window
無法透過 call、apply、bind 重新給予 this
因 箭頭函式,沒有自己的 this
,所以 this
指向全域 window
var name= '全域' |
無法作為建構式使用
const Fn = function (a) { |
promise
promise展開與其餘
陣列展開 (…Spread)
- 陣列合併
const array1 = ['HTML', 'CSS', 'JavaScript'];
const array2 = ['pug', 'sass', 'Vuejs'];
const allArray = [...array1, ...array2];
console.log(allArray) // ["HTML", "CSS", "JavaScript", "pug", "sass", "Vuejs"] - return 概念
- 淺複製 (shallow copy)
// 陣列與物件為傳參考特性
const array1 = ['HTML', 'CSS', 'JavaScript'];
const array2 = array1
array2.push('php');
console.log(array1) // (4) ["HTML", "CSS", "JavaScript", "php"]// 淺拷貝
const array1 = ['HTML', 'CSS', 'JavaScript'];
const array2 = [...array1]
array2.push('php');
console.log(array1) // (3) ["HTML", "CSS", "JavaScript"] - 類陣列轉換成純陣列
- 類陣列有如以下
- arguments(function 傳入多餘的參數)
- NodeList (document.querySelectorAll 的 DOM元素)
const f = function() {
console.log(arguments); // Arguments [1, 2, 3, 4, 5, 6]
const arg = [...arguments];
console.log(arg) // [1, 2, 3, 4, 5, 6]
arg.forEach((i)=> {
console.log(i)
})
}
f(1, 2, 3, 4, 5, 6);
參數其餘 (…Rest)
- 使用其餘參數取代
arguments
- 其餘參數產生的是純陣列
const f = function(a, ...b) {
console.log(a, b)
}
f(1, 2, 3, 4, 5, 6);
// 1
// [2, 3, 4, 5, 6]
解構賦值(Destructuring)
解構賦值可以想像是鏡子的概念,將右方的資料往左邊送,然後會一個位置對一個值 (但沒有像鏡子左右顛倒)。
解構賦值仍然是一種指定運算的語句。指定運算在等號(=
)的左邊是要被指定的變數/常數識別名稱,右邊的則是要指定的值。
陣列
使用於陣列中特別的兩點
- 可以用其餘運算符(Rest Operator)的語法,會把其餘的對應值集合成一個陣列之中。
- 可以交換(Swap)陣列中的值的語法。
- 基本用法
const [a, b] = [1, 2] //a=1, b=2
- 先宣告後指定值,需使用
let
let a, b
[a, b] = [1, 2] - 略過某些值
const [a, , b] = [1, 2, 3] // a=1, b=3
- 其餘運算符(
...
)const [a, ...b] = [1, 2, 3] //a=1, b=[2,3]
- 失敗保護
const [, , , a, b] = [1, 2, 3] // a=undefined, b=undefined
- 交換值
const a = 1, b = 2;
[b, a] = [a, b] //a=2, b=1 - 多維複雜陣列
const [a, [b, [c, d]]] = [1, [2, [[[3, 4], 5], 6]]]
- 字串
const str = "基紐特戰隊";
const [a, b, c, d, e] = str // "基", "紐", "特", "戰", "隊"
物件
物件則是使用物件的屬性名稱來做對應(因此沒有順序性)。
- 基本用法
const { user: x } = { user: 5 } // x=5
- 失敗保護(Fail-safe)
const { user: x } = { user2: 5 } // x=undefined
- 賦予新的變數名稱
const { prop: x, prop2: y } = { prop: 5, prop2: 10 } // x=5, y=10
- 預設值
const { prop: a = 5 } = {} // a = 5
- 屬性賦值語法
const { prop: prop, prop2: prop2 } = { prop: 5, prop2: 10 } //prop = 5, prop2=10
- 相當於上一項的簡短語法(Short-hand syntax)
const { prop, prop2 } = { prop: 5, prop2: 10 } //prop = 5, prop2=10
- ES7+的物件屬性其餘運算符
const {a, b, ...rest} = {a:1, b:2, c:3, d:4} //a=1, b=2, rest={c:3, d:4}
類別 (class)
class 是 ES6 推出的語法糖(JS 本質仍是原型繼承(prototype-based))
- 定義
class className {
constructor (para1, para2, ...) {
this.para1 = para1;
this.para2 = para2;
}
method1() {
// function 內容
}
// method2, method3, ...
}
let A = new className(para1, para2, ...) - 使用
class BMI_calc {
constructor (height, weight) {
this.weight = weight;
this.height = height;
}
calc() {
return Math.round(this.weight / (Math.pow((this.height / 100), 2)))
}
}
let BMI = new BMI_calc(172, 70);
console.log(BMI.calc()); // 24
縮寫 (shorthand)
- 物件縮寫
將兩個物件合併至一個物件上。- 原方式
const Frieza = '弗利沙'
const GinyuTeam = {
Ginyu: '基紐',
Jeice: '吉斯',
burter: '巴特',
}
const newTeam = {
Frieza: Frieza,
GinyuTeam, GinyuTeam
}
console.log(newTeam) // {Frieza: "弗利沙", GinyuTeam: {…}} - 縮寫
const Frieza = '弗利沙'
const GinyuTeam = {
Ginyu: '基紐',
Jeice: '吉斯',
burter: '巴特',
}
// 物件內的屬性名稱與來源變數一致時,可不需重複寫
const newTeam = {
Frieza,
GinyuTeam
}
console.log(newTeam) // {Frieza: "弗利沙", GinyuTeam: {…}}
- 原方式
- 物件內函式縮寫
- 原方式
const newObject = {
foo: function() {
// do soming
}
} - 縮寫
// 將 function 移除
const newObject = {
foo () {
// do soming
}
}
// 但使用箭頭函式結果會不一致
- 原方式
- 搭配解構使用
將以下物件指向賦予到另一個物件上,並且避免參考const GinyuTeam = {
Ginyu: {
name: '基紐'
},
Jeice: {
name: '吉斯'
},
Baata: {
name: '巴特'
}
}
const newTeam = { ...GinyuTeam };
// 可保持原物件的架構,並且不會因為傳參考特性影響
for…of
- 推薦在迭代物件屬性時,使用
for...in
;在迭代陣列時,使用for...of
。 for...in
輸出的是屬性名稱(key),for...of
輸出的是值(value)。for...of
是 ES6 的新語法。修復了ES5for...in
的不足for...of
不能迭代物件,需要透過和Object.keys()
搭配使用。
for...in |
for...of |
||
---|---|---|---|
|
|
for...in
與for...of
的差別// 在物件和陣列的原型鍊上,分別各新增function
Object.prototype.objCustom = function () {};
Array.prototype.arrCustom = function () {};
let iterable = [3, 5, 7];
// 在陣列,新增一個屬性 foo
iterable.foo = "hello";
for (let i in iterable) {
console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}
for (let i of iterable) {
console.log(i); // 3, 5, 7
}for..of
迭代 物件(object)var student={
name:'wujunchuan',
age:22,
locate:{
country:'taiwan',
city:'taipei',
school:'UCCU'
}
}
for(var key of Object.keys(student)){
//使用Object.keys()方法獲取物件key的陣列
console.log(key+": "+student[key]);
}
import & export
ES6的模組系統使用上相當簡單
- ES6的模組程式碼會自動變成
strict-mode
(嚴格模式),不論你有沒有使用"use strict"
在程式碼中。 - ES6的模組是一個檔案一個模組
- ES6模組使用
export
(輸出)與import
(輸入)語句來進行模組輸出與輸入。輸出通常位於檔案最後,輸入位於最前面。 export
分別有export
跟export default
,兩者最大的差異是export
可以有多個,但export default
只能存在一個。
export
export const arr = [1, 2, 3, 4]; |
有兩種方式可以將以輸出的模組進行輸入。
- 解購賦值方式,可另外 alias 一個模組名稱
import { arr, aFunction, aClass } from "./module.js";
import { aString as myString } from "./module.js";
console.log(arr);
console.log(myString);
aFunction() - 使用萬用字元
*
但需要 alias 一個模組名稱import * as myModule from './module.js'
console.log(myModule.arr);
console.log(myModule.aFunction())
const newObj = new myModule.aClass('Inori', 16);
console.log(newObj)
export default
對單一輸出的模組就不需要使用解構賦值,這代表只輸入以 default 值定義的輸出模組。
function aFunction(param){ |
import aFunction from './module.js' |