.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號: N161017601
出刊日期: 2016/10/05
ECMAScript 6截至2015年功能大多已經完整定義完成,因此ECMAScript 6又稱ECMAScript 2015,但目前並非所有瀏覽器都支援此規範所定義的完整功能,要在網站應用程式使用到ECMAScript 6的語法之前,建議先查詢瀏覽器的支援程度,再決定是否使用,可參考http://kangax.github.io/compat-table/es6/網站。
ECMAScript 2015提供許多新物件、語法來協助開發JavaScript程式,本文將介紹ECMAScript 2015的一些新語法。
線上測試工具
由於不是每個瀏覽器都有支援ECMAScript 2015的所有語法,因此你可以利用一些現成的線上工具,來進行測試,例如Babel網站提供的線上工具網址在:https://babeljs.io/repl/,網頁畫面請參考下圖所示:

圖 1
畫面的左方是ECMAScript 2015程式碼,當你輸入程式碼,右方會自動轉譯成ECMAScript 5的語法,右下方則是執行的結果。
宣告區塊等級變數
ECMCScript 5預設只有函數範圍(function scope)與全域範圍(global scope)等級的變數,例如以下ECMCScript 5 範例程式碼,在if區塊中,使用var宣告變數x,在if區塊之內和之外,都可以存取到x變數的值:
if (true) {
var x = 10;
console.log(x); // 10
}
console.log(x); // 10
在ECMAScript 2015中,可以改用let來宣告x變數,使用var宣告的變數有效範圍在一個function之中;使用let宣告的變數有效範圍在一個區塊(block)之中,區塊以{}符號括起來,當程式執行超過一個區塊後,變數便不復存在,在此區塊之外的程式碼無法讀取到它。參考以下範例程式碼,只有if區塊中的程式碼可以存取到變數x的值,超過if區塊存取x變數就會發生例外錯誤:
if (true) {
let x = 10;
console.log(x); // 10
}
console.log(x); // 錯誤
此外變數需要先宣告,才能夠存取,例如以下範例程式碼,在if區塊中,先印出x值,再定義x變數,執行將發生錯誤,而let那行定義變數的程式碼,將沒有機會執行:
if (true) {
console.log(x); // 錯誤
let x = 10;
}
console.log(x); // 10
建議儘量使用let關鍵字來取代之前的var關鍵字宣告變數。
變數名稱不可重複宣告
若變數已使用var關鍵字宣告,那麼在變數有效範圍內,就不可以再使用let關鍵字重複進行宣告,否則會發生例外錯誤。例如以下程式碼,第一行已經使用var宣告x變數;緊接著第二行又使用let來宣告同名的x變數,則let那行程式碼會發生錯誤:
var x = 10;
let x = 20; // 錯誤
if (true) {
console.log(x);
}
console.log(x);
但是,參考以下範例程式碼,若在if區塊中使用let關鍵字宣告變數x則不會發生錯誤,let那行程式其變數的有效範圍在if區塊,而使用var宣告的變數視為全域變數:
var x = 10;
if (true) {
let x = 20;
console.log(x); // 20
}
console.log(x); // 10
在迴圈宣告變數
在ECMAScipt 5中,若在迴圈中使用var宣告變數,執行超過迴圈的範圍,還是可以讀到它的值,這是JavaScript預設自動提升(hoisting)變數的能力所造成的,例如以下範例程式碼,進行一到一百的累加運算,執行超過for迴圈後,在for迴圈之外,還是可以讀到i變數的值:
var total = 0;
for (var i = 0; i < 100; i++) {
total += i;
}
console.log(total); //4950
console.log(i); //100
若改用let關鍵字來宣告變數值,則在for迴圈之外,適著讀取i變數的值就會產生錯誤,參考以下範例程式碼:
var total = 0;
for (let i = 0; i < 100; i++) {
total += i;
}
console.log(total); //4950
console.log(i); //錯誤
在全域範圍宣告變數
若使用var在全域範圍(Global Scope)宣告變數,變數會成window物件的屬性,後續可以利用window物件來存取,例如以下範例程式碼,定義一個x變數,我們可以使用屬性的語法,windows.x來讀取變數值:
var x = 10;
console.log(x); // 10
console.log(window.x); // 10;
而使用let關鍵字宣告的變數,則不會成為window物件的屬性,參考以下範例程式碼,定義一個x變數,若使用屬性的語法,windows.x來讀取變數值則會印出「undefined」:
let x = 10;
console.log(x); // 10
console.log(window.x); // undefined;
宣告常數
在EMCAScript 2015中可以使用const關鍵字來宣告常數,用於宣告唯讀的變數,意指常數一經宣告,就不能夠更改它的值。
參考以下範例程式碼使用const參考宣告一個常數x,若宣告後試圖修改常數的值,就會發生錯誤:
const x = 10;
console.log(x); // 10
x = 100; // 錯誤
console.log(x);
此外要注意,宣告常數時一定要給予初始值,否則也會產生錯誤,參考以下範例程式碼:
const x ; //錯誤
使用const關鍵字和let關鍵字宣告的變數一樣,const常數的有效範圍在一個區塊之中,超過區塊的範圍則不可存取。例如以下範例程式碼在if區塊中,使用const關鍵字宣告常數x,在if區塊之內,可以存取到x常數的值,超過if存取就會發生錯誤:
if (true) {
const x = 20;
console.log(x); // 20
}
console.log(x); // 錯誤
常數名稱不可重複宣告
若常數已使用var關鍵字宣告了,那麼在有效範圍內,就不可以再使用const關鍵字重複進行宣告,否則會產生例外錯誤,例如以下範例程式碼,const那行宣告的程式碼將會發生錯誤:
var x = 10;
const x = 20; // 錯誤
if (true) {
console.log(x);
}
console.log(x);
但是若已使用var關鍵字宣告了常數,在if區塊中使用const關鍵字宣告同名的常數,則不會發生錯誤,參考以下範例程式碼,const那行常數的有效範圍在if區塊,而使用var關鍵字宣告的變數視為全域變數,因此程式可分別印出x的值:
var x = 10;
if (true) {
const x = 20;
console.log(x); // 20
}
console.log(x); // 10
變更常數值
如前文所提,使用const宣告的變數,在程式執行的過程中,不能夠修改它的值,否則會產生錯誤。但若使用const來宣告物件,則物件中的屬性值是可以修改的。例如以下範例程式碼,employee物件包含name與age兩個屬性,可以在後續程式中改變它們的值,因為程式中改變的是employee包含的屬性值,而不是employee本身:
const employee = {
name: "Mary",
age: 30
}
console.log(employee.name); // mary
console.log(employee.age); // 30
employee.name = "Candy";
employee.age = 40;
console.log(employee.name); // candy
console.log(employee.age); // 40
但若修改程式碼如下,在程式的最後,試著改變employee常數的值,就會出現錯誤:
const employee = {
name: "Mary",
age: 30
};
console.log(employee.name); // mary
console.log(employee.age); // 30
employee.name = "Candy";
employee.age = 40;
console.log(employee.name); // candy
console.log(employee.age); // 40
//錯誤
employee = {
name: "Mary",
age: 30
};
八進位與二進位常值
八進位
若要表示八進位數值可以在數值前方使用「0o」(零歐)。在ECMAScript 5之前,數值前方加0(零),表示八進位,例如以下範例程式碼,使用八進位表示數值9:
var o1 = 011;
console.log(o1); // 9
而ECMAScript 2015則使用「0o」(零歐)開始,參考以下範例程式碼,使用八進位表示數值9的寫法���
var o2 = 0o11;
console.log(o2); // 9
預設JavaScript會將十六進位與八進位的數值轉換成十進位,然後以二進位的方式儲存。
二進位
若要表示二進位數值可以在數值前方使用「0b」(零b),參考以下範例程式碼:
var b = 0b11;
console.log(b); //3
字串處理
在EMCAScript 2015為字串提供了許多新方法,來操作字串,例如去除字串左方、右方空白,判斷字串是否以某個字元開始或結束...等等,最重要的特色是,提供多行字串的處理,以及樣版常值(Template Litarals)。以下分別說明這些新增的功能。
使用trimLeft()方法與trimRight()方法
在EMCAScript 5版,若要去掉字串前後的空白只有一個trim()方法可以使用,無法只去除字串前方或後方空白,現在可以使用trimLeft()方法或trimRight()方法來解決這個問題。trimLeft()方法用來去除字串前方空白;trimRight()方法用來去除字串後方空白,參考以下範例程式碼:
let s = " Mary ";
console.log("[" + s.trim() + "]"); // [Mary]
console.log("[" + s.trimLeft() + "]"); // [Mary ]
console.log("[" + s.trimRight() + "]"); //[ Mary]
使用includes()方法
若要判斷字串中是否包含特定的文字,可以使用includes()方法,若includes()方法回傳true代表有包含指定的字串,若includes()方法回傳false,則代表不包含指定的字串,例如以下範例程式碼:
let s = "This is a book";
console.log(s.includes("book")); // true
console.log(s.includes("pen")); // false
使用startsWith()方法與endsWith()方法
startsWith()方法可以偵測字串是否以特定字元開始;而endsWith()方法則可用來評估字串是否以特定字元結束,這兩個方法都會回傳一個布林值來回報測試的結果,例如以下範例程式碼:
let s = "This is a book";
console.log(s.startsWith("This")); // true
console.log(s.endsWith("book")); // true
startsWith()方法與endsWith()方法都可以選擇性地傳入第二個參數,代表字串是否從此索引值開始出現。參考以下範例程式碼,startsWith()方法的程式碼判斷「is」字串是否是從原始字串「s」的索引5位置開始出現,endsWith()方法的程式碼判斷「is」字串是否結束在原始字串「s」索引7的位置:
let s = "This is a book";
console.log(s.startsWith("is",5)); // true
console.log(s.endsWith("is",7)); // true
使用repeat()方法
repeat()方法用來產生重複的字串,參考以下範例程式碼,重複產生「x」字串10次:
let s = "x";
console.log(s.repeat(10)); // xxxxxxxxxx
參考以下範例程式碼,重複產生「Hi」字串10次:
let s = "Hi";
console.log(s.repeat(10)); // HiHiHiHiHiHiHiHiHiHi
想要重複產生中文也沒問題,參考以下範例程式碼,重複產生「中文」字串10次:
let s = "中文";
console.log(s.repeat(10)); //中文中文中文中文中文中文中文中文中文中文
使用樣版常值(Template Literals)
樣版常值(Template Literals)可以簡化多行文字格式化的動作,以「`」(backticks)符號來定義樣版,樣版常值(Template Literals)基本上就是字串。
參考以下範例程式碼,使用let關鍵字宣告一個變數s,其中包含樣版常值(template literals),以「`」符號將字串括起來。樣版中可用「${變數名稱}」語法將變數的值代入,以本例來說 ${t} 代表定位點,它的值會由變數t的內容取代:
let t = new Date().getHours();
let s = `It is ${t}`;
console.log(t); // 12
console.log(s); // It is 12
console.log(typeof s); // string
console.log(s.length); // 8
再者樣版常值(Template Literals)內也可以進行簡單的運算,參考以下範例程式碼,計算目前的小時加一小時的結果:
let t = new Date().getHours();
let s = `It is ${t+1}`;
console.log(t); // 12
console.log(s); // It is 13
console.log(typeof s); // string
console.log(s.length); // 8
樣版常值(Template Literals)中也可以包含呼叫函式的程式碼,參考以下範例程式碼,有一個getHoursPlus1()函式,樣版常值中使用「${getHoursPlus1()」來呼叫函式,將函式的回傳值插入「${getHoursPlus1()」所在的位置:
let s = `It is ${getHoursPlus1()}`;
console.log(s); //It is 13
function getHoursPlus1() {
let t = new Date().getHours();
console.log(t); // 12
return t + 1;
}
樣版常值(template literals)中若使用單引號或雙引號,它們都被視為文字,參考以下範例程式碼,樣版常值中使用「"${t}"」將變數值包起來:
let t = new Date().getHours();
let s = `It is "${t}"`;
console.log(t); // 12
console.log(s); // It is "12"
若樣版常值(template literals)中包含「`」(backticks)符號,則要使用跳脫字元「\」(backslash),參考以下範例程式碼:
let t = new Date().getHours();
let s = `It is \`${t}\``;
console.log(t); // 12
console.log(s); // It is `12`
樣版常值的好處是,冗長的文字字串,在設計階段可以以多行的方式輸入,參考以下範例程式碼,在ECMAScript 5之前,文字換行要使用「\」符號表示,範例程式將輸出一行文字「This is a book」:
var s = "This \
is \
a \
book";
console.log(s); //This is a book
在ECMAScript 2015改用樣版常值就可以省略掉「\」符號,參考以下範例程式碼,字串會根據樣版常值的定義,換行呈現:
var s = `This
is
a
book`;
console.log(s); //This
//is
//a
//book
使用Tagged Templates
若樣版常值還無法滿足你複雜的字串組合邏輯,ECMAScript 2015還提供了Tagged Templates,讓你自行客製化組合字串,並回傳一個字串。只要在樣版開始的「`」符號之前指定一個標記(tag),並定義一個和標記(tag)同名的函數來組合字串,參考以下範例程式碼:
let h = new Date().getHours();
let m = new Date().getMinutes();
let s = mytagTemplate`It is ${h}:${m}`;
console.log(s); // It is [15]:[32]
function mytagTemplate(literals, ...substitutions) {
let r = "";
for (let i = 0; i < substitutions.length; i++) {
r += literals[i];
r += "[" + substitutions[i] + "]";
}
return r;
}
mytagTemplate是我們自訂的標記,標記後「`」符號中的內容會傳到mytagTemplate 方法做處理。mytagTemplate方法的literals參數是一個陣列,存放在樣版常值(template literals)中文字常值,而substitutions參數也是一個陣列,存放所有要替代的變數值。從除錯工具可以更深入了解其中包含的內容,參考下圖是這段程式碼的執行結果:

圖 2
使用原始資料
String.raw()是一個內建的標記,以存取原始的字串內容。參考以下範例程式碼,若有一個樣版常值中包含跳脫字元「\」,則輸入的結果為「It is '16':'02'」:
let h = new Date().getHours();
let m = new Date().getMinutes();
let s =`It is \'${h}\':\'${m}\'`;
console.log(s); //It is '16':'02'
使用String.raw(),則跳脫字元「\」將會被保留:
let h = new Date().getHours();
let m = new Date().getMinutes();
let s = String.raw`It is \'${h}\':\'${m}\'`;
console.log(s); //It is \'16\':\'2\'