一、ECMAScript的介紹與環境配置
1. 簡介
ECMAScript是JavaScript的版本標準,在2015年6月發行。我們通常學習的JavaScript指的是ES3。
2. 環境配置
使用ES6我們需要安裝Node.js,Node.js是運行在服務器端的JavaScript,對ES6的支持度更高。
二、聲明與表達式
1. let與const
let關鍵字
let關鍵字和var關鍵字相似,都是聲明變量的時候使用的,然而let關鍵字和var關鍵字有一定區別
- 代碼塊內有效:let命令只有在let所在的代碼塊有效,而var全局有效
- 不能重複聲明:let只能聲明一次,var可以聲明多次
- 不存在變量提升:var關鍵字會變量提升,及開始運行的時候變量已經存在了,在賦值之前是undefined;而let關鍵字不會變量提升,如果再聲明和賦值之前引用變量會報錯
const關鍵字
const關鍵字聲明一個只讀變量,聲明之後不可以改變,一旦聲明必須初始化。
注意,ES6規定,一個代碼塊中存在let或者const,會讓這個代碼塊的作用域封閉,即使外部作用域有相同名稱的變量也無法訪問。
const關鍵字保證的實際上不是值不變,而是引用對象的指針不發生改變,因此const修飾簡單類型(number, string, boolean)相當於定義常量,而當const修飾複雜對象的時候只能確保指針是固定的,指針指向的數據結構是否改變是無法控制的,因此const修飾複雜對象要慎重。
2. 解構賦值
解構賦值是賦值的擴展,針對於數組或對象進行模式匹配,並對其中的變量進行賦值。
數組模型的解構
let [a,b,c] = [1,2,3];
// a = 1
// b = 2
// c = 3
數組的解構賦值有以下幾個特點
- 可嵌套:
let[a, [[b], c]] = [1, [[2], 3]];
- 可忽略:
let [a, , b] = [1, 2, 3];
- 不完全解構:
let [a, , b] = [1, 2, 3];
- 剩餘運算符:
let [a, ...b] = [1, 2, 3];
- 使用字符串:
let [a,b,c,d,e] = 'hello'
- 結構默認值:
let [a=2] = [undefined] // a = 2
,掃描到undefined返回默認值
對象模型的解構
let {foo, bar} = { foo: 'aaa', bar:'bbb'};
// foo = 'aaa'
// bar = 'bbb'
let {baz: foo} = {baz: 'ddd'};
// foo = 'ddd'
- 可嵌套可忽略
- 不完全解構:
let obj = {p: [{y: 'world'}]}; let {p:[{y}, x]}= obj; // x = undefined
- 剩餘運算符:
let {a, b, ...rest} = {a:10, b:20, c:30, d:40}; // rest = {c:30,d:40}
- 結構默認值:
let {a:aa = 10, b: bb= 5} = {a:3}; // aa = 3, bb = 5
3. Symbol
Symbol是一種原始數據類型,表示獨一無二的值,來定義對象的唯一屬性名。ES6中數據類型除了Number、String、Boolean、Object、null、undefined,還新增了Symbol。
Symbol類型的變量不能用new關鍵字實例化,因爲Symbol是原始數據類型,不是對象,可以接收一個字符串類型的變量作爲參數,來提供描述。Symbol類型的每一個變量都不相等。Symbol可以作爲對象的變量名,可以保證屬性不重名。
Symbol作爲對象屬性名的時候不能使用.運算符,要使用方括號,否則取到的值爲undefined。因爲.後面是字符串,所以取到的是字符串屬性,而不是Symbol屬性。Symbol作爲屬性名時,屬性是公有的,而不是私有的,可以在類的外部訪問。但是不會出現在for…in,for…of的循環中,也不會被Object.keys()、Object.getOwnPropertyNames()返回。可以通過Object.getOwnPropertySombols()和Reflect.ownKeys()取得。
Symbol.for()方法類似單例模式,會在全局搜索是否有給定的字符串作爲參數的Symbol值,若有則返回該Symbol值,若沒有則返回一個以該字符串爲參數的Symbol值,並在全局登記。
Symbol.keyFor()會根據給定的Symbol變量的變量名返回Symbol變量中的字符串值。
三、內置對象
1. Map與Set
Map對象
Map對象保存鍵值對,任何原始值或對象都可以作爲鍵,而Object的鍵只能是字符串或Symbol。
Map獨享使用set()和get()來存儲和訪問,key可以是原始值、對象、函數或者Nan。
Map對象可以使用for…of和forEach來進行遍歷
for (var [key, value] of myMap){
console.log(key + "=" + value);
}
for (var [key, value] of myMap.entries()){
console.log(key + "=" + value);
}
for (var key of myMap.keys()){
console.log(key);
}
for (var valueof myMap.values()){
console.log(value);
}
myMap.forEach(function(value,key){
console.log(key + " = " + value);
}, myMap)
除此之外,Map對象還有以下的操作
- Array轉換Map
myMap = new Map(array);
- Map轉換Array
array = Array.from(myMap);
- Map的克隆
myMap2 = new Map(myMap1);
- Map的合併
var merged = new Map([...first, ... second]);
Set對象
Set對象存儲的值總是唯一的,即Set對象無法存儲重複的值。注意:+0和-0不重複,undefined和undefined不重複,Nan和Nan不重複。
Set對象有以下的操作:
- Array轉換爲Set
var set = new Set(["value1", "value2", "value3"]);
- Set轉換爲Array
var array = [...set]
- 取並集:
var union = new Set([...a,...b]);
- 取交集:
var intersect = new Set([...a].filter(x => b.has(x)));
- 取差集:
var difference = new Set([...a].filter(x => !b.has(x)));
2. Reflect與Proxy
Proxy
Proxy像是代理模式,不直接操作對象,而是對對象的讀取、調用等操作進行攔截並處理。
Proxy是由target和handler兩個部分組成的,target是原來的對象,handler來實現對應的功能
let target = {
name: 'Tom',
age: 24
}
let handler = {
get: function(target){
return target[key];
}
set: function(target,key,value){
target[key] = value;
}
}
let proxy = new Proxy(target, handler);
proxy.name
proxy.age = 25
其中target可以是空對象,handler也可以是空對象,相當於不設置攔截操作。另外,目標對象和代理對象是淺拷貝關係,對一者的改變會影響另一者。
常用的可攔截的方法有:
get(target, propKey, receiver)
:用於target對象上propKey的讀取,可繼承set(target, propKey, value, receiver)
:用於攔截target對象上propKey的賦值apply(target,ctx,args)
:用於攔截函數的調用、call和replyhas(target, propKey)
:判斷target是否有某屬性construct(target, args)
:用於攔截new關鍵字,返回值必須爲對象deleteProperty(target, propKey)
:用於刪除屬性,如果報錯或返回false,則無法刪除defineProperty(target, propKey, propDesc)
:用於添加屬性,若返回false,則無法添加getOwnPropertyDescriptor(target, propKey)
:返回屬性的描述getPrototypeOf(target)
:獲取對象原型isExtensible(target)
:只能返回布爾值,否則會被強轉爲布爾值ownKeys(target)
:返回所有屬性的名稱preventExtensions(target)
:該方法必須返回一個布爾值,否則會強轉爲布爾值
Reflect
ES6將一些Object的屬於語言內部的方法移植到了Reflect對象上。下面我們來列舉一下常見的方法
Reflect.get(target, name, receiver);
:返回target的name屬性Reflect.set(target, name, value, receiver);
:將target的name設置爲value。返回一個布爾值結果Reflect.has(obj, name);
:查找name屬性在obj對象中是否存在Reflect.deleteProperty(obj, property);
:刪除obj對象的property屬性,返回一個布爾值結果Reflect.construct(obj, args);
:相當於new target(..args);
Reflect.apply(func, thisArg, args);
:func表示目標函數,thisArg寶石目標函數綁定的this對象,args表示函數的參數Reflect.defineProperty(target, propertyKey, attributes)
:定義屬性Reflect.getOwnPropertyDescriptor(target, propertyKey);
:獲得屬性的描述Reflect.isExtensible(target)
:查看一個對象是否可擴展Reflect.preventExtension(target)
:讓一個對象不可擴展
一般來講Proxy和Reflect是組合使用的,下面我們用它們來實現一個觀察者模式
const queuedObservers = new Set();
const observe = fn => queuedObservers.add(fn);
const obserbale = obj => new Proxy(obj, {set});
function set(target, key, value, receiver){
const result = Reflect.set(target, key, value, receiver);
queuedObservers.forEach(observer => observer());
return result;
}
3. 字符串
ES6新增了識別字串的方法
includes(str)
:判斷是否找到參數字符串,返回布爾值startsWith(str)
:判斷參數字符串是否在源字符串的頭部,返回布爾值endsWith(str)
:判斷參數字符串是否在源字符串的尾部,返回布爾值
需要注意的是,這三個函數不能將正則表達式作爲參數傳入,只能直接接收字符串
除了字符串的識別,還增加了其他方法
- 字符串重複:
console.log("HelloWorld ".repeat(2));
- 字符串補全:
console.log("h".padStart(5,'o'));
同樣也有padEnd();
,默認填充字符爲空格 - 模板字符串:`Hello’\n’World`,或者是
let name = "Mike";
let age = 25;
let info = `My Name is ${name}, I am ${age + 1} years old next year.`;
function f(){
return "have fun!"
}
let string2 = `Game start, ${f()}`;
- 標籤模板:把後面的模板字符串傳入前面的函數中,例如
alert`Hello World!`;
alert('Hello World!');
可以使用在過濾惡意輸入,或轉化其他語言等功能上
4. 數值
數值的改動如下
- 二進制可以添加前綴:0b或0B
- 八進制可以添加前綴:0o或0O
- 新增常量Number.EPSILON,其值是1與大於1的最小浮點數之間的差(2.2204460492503130808472633361816E-16)
- 添加最大/最小安全整數,表示能夠精確表示的整數,在2^-53到2^53之間
通過Number.MAX_SAFE_INTEGER
和Number.MIN_SAFE_INTEGER
來訪問 Number.isFinite(num)
:查看一個數值是否是InfinityNumber.parseInt()
:第一個參數是給定的數字,第二個參數是要轉換的進制
5. 對象
ES6中可以直接使用變量定義對象,也可以直接定義對象
const age = 12;
const name = "Amy";
const person = {age, name};
// 等同於
const person = {age: 12, name:"Amy"};
對象中可以定義函數,可以簡寫
const person = {
sayHi(){
console.log("Hi");
}
}
// 等同於
const person = {
sayHi:function(){
console.log("Hi");
}
}
const person = {
*myGenerator(){
yield 'Hello World';
}
}
// 等效於
const person = {
myGenerator: function*(){
yield 'Hello World';
}
}
對象同樣可以使用表達式作爲屬性名,但必須放在方括號中
const obj = {
["hel"+"lo"](){
console.log("Hello");
}
}
注意,屬性的簡介寫法和屬性名錶達式不能同時使用,否則會報錯
對象也可以使用拓展運算符,用於對象的複製或合併。我們可以在拓展運算符後面添加自定義屬性,同名的會被覆蓋
let person = {name:"Amy",age:12};
// 複製
let someone = {...person}
let info = {gender:"female"}
// 合併
let amyInfo = {...person, ...info};
// 添加自定義屬性
let amyInfo = {...person, ...info, id:1,code:"1A"};
對象添加了以下兩個新方法
Object.assign(target, source_1, ...)
把從第二個參數開始的屬性添加到第一個對象中,其中的屬性拷貝是淺拷貝Object.is(value1,value2)
判斷兩個對象是否嚴格相等
6. 數組
數組
數組可以通過下面的方法來新建
Array.of(value1,value2,...)
:將參數傳入數組,參數可以爲不同類型,也可以返回空數組Array.from(iterable)
:將一個可迭代對象轉化爲數組,可以含有空數位
初此之外,數組還有這些新方法
arr.find(item => item > 2);
:查找數組中符合條件的元素,若有多個元素,則返回第一個arr.findIndex(item => item = 1);
:查找數組中符合條件的索引,如果有多個索引,則返回第一個arr.fill(a,b,c);
:將一定範圍內的數組元素內容填充爲單個指定值,a是用來填充的值,b是被填充的起始索引,c是結束的索引arr.copyWithin(a,b,c)
:將一定範圍內的數組元素修改爲此數組另一個元素,a是被修改的起始索引,b是被用來覆蓋的數據的索引,c是結束索引arr.entries()
:遍歷鍵值對,裏面是索引和元素arr.keys()
:遍歷鍵名,裏面是索引arr.values()
:遍歷元素值arr.includes(item)
:某元素是否存在於數組中[1,2.[3,4]].flat(); // [1,2,3,4]
:嵌套數組轉爲一維數組[1,2,3].flatMap(n => [n * 2]); // [2, 4, 6]
:對每個元素執行指定函數,再執行flat()函數
數組緩衝區
數組中還有數組緩衝區對象,是內存中的一段地址,也就是其它語言中的定型數組。數組的長度在創建的時候被確定,只能修改內容,不能修改長度。
let buffer = new ArrayBuffer(10);
console.log(buffer.byteLength); // 10
let buffer1 = buffer.slice(1,3);
console.log(buffer1.byteLength); // 2
視圖
視圖是用來操作數組緩衝區的子集,並按照一種數據類型讀取和寫入數據
let buffer = new ArrayBuffer(10);
let dataView = new DataView(buffer);
dataView.setInt(0,1);
console.log(dataView.getInt8(0)); // 1
// 設置偏移量(參數2)和長度(參數3)來控制DataView操作字節範圍
let dataView2 = new DataView(buffer, 0, 3);
dataView2.setInt(5,1); // RangeError
定型數組
定型數組強制使用特定的數據類型,而不是通過DataView對象來操作數組緩存區。
// 通過數組緩存區生成
let buffer = new ArrayBuffer(10), view = new Int8Array(buffer);
// 通過構造方法
let view = new Int32Array(10);
定型數組的length屬性代表長度,不可寫。定型數組可以使用entries()、keys()和values()來迭代。find方法等方法也可應用於定型數組,但會額外檢查類型是否匹配;定型數組也有of和from方法,區別在於返回值也是定型數組。
參考資料
[1] 菜鳥教程ES6
歡迎加入交流羣QQ1107710098