《ES標準入門》&《UNDERSTANDING ECMACHRIPT 6》 讀書摘錄筆記(上)
### 前言
*這兩本書應該是目前ES6相關的比較好的了,網上有電子版本(文末有鏈接)。不過我買了書看,哈哈。這兩篇摘錄筆記分為上下兩部分,本文是上半部分(1-6章),摘錄了兩本書裏一些比較有用的知識點。*
### 目錄
> #####1. 塊級作用域綁定
> #####2. 字符串與正則表達式
> #####3. 函數的擴展
> #####4. 數組的擴展
> #####5. 對象的擴展
#####6. 集合(Set、Map)
> 7 . Symbol和Symbol屬性
>
> 8 . Javascript中的類
>
> 9 . Promise、Generator函數、Async函數
>
> 10 . 代理(Proxy)和反射(Reflection)API
>
> 11 . 修飾器
>
> 12 . Module
### 一、塊級作用域綁定
塊級聲明用於聲明在指定塊級作用域之外無法訪問的變量。塊級作用域存在於:1、函數內部;2、塊中(字符‘{‘和‘}‘之間的區域)。Es6 中存在的兩種變量聲明就是Let和Const聲明。
值得摘錄的有以下六點:
##### 1. 不能重復聲明
var count = 9;
//拋出語法錯誤
let count = 7;
##### 2. Const常量聲明必須進行初始化
const age = 8;
//語法錯誤:常量未初始化
const name;
##### 3. 特殊的For循環
For循環設置循環變量的那部分是一個父作用域,而循環體內部是一個單獨的子作用域。
for(let i = 0;i< 3;i++){
let i = ‘can not change‘;
console.log(i);//輸出‘can not change‘
}
##### 4. 暫時性死區
在區塊中存在let和const命令,則這個區塊對這些命令聲明的變量從一開始就形成封閉的作用域。只要在聲明之前就使用這些變量,就會報錯。
情況一:
var tmp = 123;
if(true){
tmp = ‘abc‘;//ReferenceError
let tmp;
}
情況二:
function test(x = y,y = 2){
return [x,y];
}
test();//報錯
情況三:
let x = x;//ReferenceError: x is not defined
##### 5. Const聲明對象,對象屬性可變
##### 6. 徹底凍結函數
constantize(obj) {//徹底凍結函數
Object.freeze(obj);
Object.keys(obj).forEach((key, i) => {
if (typeof obj[key] === ‘object‘) {
constantize(obj[key]);
}
})
obj.name = 777;//TypeError: Cannot add property name, object is not extensible
return obj;
}
### 二、字符串與正則表達式
Es6加強了對Unicode的支持,並且擴展了字符串對象。正則表達式則增加了修飾符和屬性。
值得摘錄的有以下幾點:
##### 1. codePointAt()與String.fromCodePoint()方法
完全支持UTF-16,接受編碼單元的位置而非字符位置作為參數,返回與字符串中給定位置對應的碼位,即一個整數值:
var text = "??a";
console.log(text.charCodeAt(0)); //55362
console.log(text.codePointAt(0)); //134017
判斷一個字符是2個字節還是4個字節組成:
function is32Bit(c){
return c.codePointAt(0) > 0xFFFF;
}
is32Bit("??"); // true
is32Bit("a"); // false
console.log(String.fromCodePoint(134071)); // "??"
##### 2. normalize()方法
Es6為字符串添加了一個Normalize()方法,它可以提供Unicode的標準化形式,接受一個參數,指明應用哪種Unicode標準化形式(NFC,NFD,NFKC,NFKD)。只需要記住,在對比字符串之前,一定要先把它們標準化為同一種形式:
let normalized = values.map((text) => {
return text.normalize();
})
console.log(this[normalize](‘\u01D1‘) === this[normalize](‘\u004F\u030C‘)) // true
##### 3. includes()、startsWith()、endsWith()、repeat()方法
let tempArray = [1, "4", "uu", 5];
let tempStr = "test123uuunit582";
console.log(tempArray.includes(5)); //true
console.log(tempStr.includes("test123", 1)); //從第二個位置進行匹配
console.log(tempStr.startsWith("test")); //true
console.log(tempStr.startsWith("test123", 0)); //從第一個位置進行匹配
console.log(tempStr.endsWith("12",6)); //從第六個位置進行匹配
console.log(tempStr.repeat(3)); //test123uuunit582test123uuunit582test123uuunit582
##### 4. 模板字符串
領域專用語言(DSL),可以生成、查詢並操作其他語言裏的內容,且可以免受註入攻擊(XSS、SQL等)。
> A、去掉模板字符串中的換行
$(‘#list‘).html(`
<ul>
<li>first</li>
<li>second</li>
</ul>
`.trim());
> B、引用模板字符串本身
//寫法一
let str = ‘return ‘ + ‘`ni hao ${name}`‘;
let func = new Function(‘name‘,str);
let data = func(‘uct‘);
//寫法二
let str2 = ‘(name) => `ni hao ${name}`‘;
let func2 = eval.call(null,str2);
let data2 = func2(‘uct‘);
console.log(data + ‘ ‘ + data2);
> C、標簽模板
alert`123`;
//等同於
alert(123);
var a = 1,b = 2;
tag`Hello ${a + b} world ${a * b}`;
//等同於
tag([‘Hello ‘,‘ world , ‘‘],1,2);//第一個參數是數組,存放模板中沒有變量替換的部分,後續參數是變量。
> D、String.raw()轉義模板字符串
String.raw`Hi\n${3+4}`;//"Hi\\n5"
[關於new Function][newFunction]
[關於eval][eval]
[newFunction]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function
[eval]:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/eval
##### 5.U修飾符與Y修飾符
U修飾符,即為“Unicode模式”,用來正確處理大於\uFFFF的Unicode字符。Y修飾符,叫作“粘連”(Sticky)修飾符,它的後一次匹配都從上一次匹配成功的下一個位置開始。
> A、點(.)字符匹配(匹配除換行符外的所有字符)
var s = "??";
/^.$/.test(s); // false
/^.$/u.test(s); // true
> B、返回字符串長度的函數
function codePointLength(){
var result = text.match(/[\s\S]/gu);
return result ? result.length : 0;
}
> C、y修飾符隱含了頭部匹配的標誌(^)
const REGEX = /a/y;
REGEX.lastIndex = 2;
REGEX.exec("xaya"); // null
REGEX.lastIndex = 3;
const match = REGEX.exec("xaya");
match.index; // 3
### 三、函數的擴展
值得摘錄的有以下幾點:
##### 1.函數參數的默認值
> A、參數變量默認聲明
function test(x = 1){
let x = 2;//error
}
> B、惰性求值
let x = 10;
function testLazy(p = x + 1){
console.log(p);
}
testLazy(); // 11
let x = 12;
testLazy(); // 13
> C、非尾部設置默認值,參數不可省略
function f(x = 1,y){
return [x,y];
}
f(,1); //報錯
> D、默認參數的臨時死區TDZ
function add(first = second,second){
return first + second;
}
console.log(add(1,1)); // 2
console.log(add(undefined,1)); // 拋出錯誤
//當初次調用add()時,綁定first和second被添加到一個專屬於函數參數的臨時死區
//表示調用add(1,1) 時的Javascript 代碼
let first = 1;
let second = 2;
//表示調用add(undefined,1) 時的Javascript 代碼
let first = second;
let second = 1; //所以拋出錯誤;
##### 2.默認參數表達式
初次解析函數聲明時不會調用getValue()方法,只有當調用add()函數且不傳入第二個參數時才會調用:
constructor() {
this.value = 5;
}
getValue(){
return this.value ++;
}
add(first,second = this.getValue()){
console.log(‘plus: ‘, first + second );
}
...
Es6Function.add(1,1); // plus: 2
Es6Function.add(1); // plus: 6
Es6Function.add(1); // plus: 7
##### 3. 只要函數參數使用了默認值、解構賦值或者擴展運算符,那麽函數內部就不能嚴格模式
const doSomething = (a,b = a,...c) => { //error
‘use strict‘;
//code
}
##### 4. 不定參數限制使用
> 每個函數最多只能聲明一個不定參數,而且一定要放在所有參數的末尾。
function any(a,...b,last){} //報錯
> 不定參數不能用於對象字面量Setter中
let object = {
//語法錯誤,不可以在Setter中使用不定參數
set name(...value){}
}
> 取數組最大值
let values = [25,34,11,99];
console.log(Math.max(...values)); // 99
##### 5. 箭頭函數
> A、箭頭函數中的This值取決於該函數外部非箭頭函數的this值,且不能通過call()、apply()或bind()方法來改變this值
thisScope(){
setTimeout(()=>{
console.log(‘id: ‘,this.id);
},100);
}
...
var id = 55;
Es6Function.thisScope.call({id:100}); // id : 100
> B、函數體內不可民使用Arguments對象,該對象在函數體內不存在,可以用Rest參數(...)代替
testArguments(){
setTimeout(() => {
console.log(‘args: ‘,arguments)
}, 100);
}
...
Es6Function.testArguments(1,2,5,6); // args: Arguments(4) [1, 2, 5, 6, callee: (...), Symbol(Symbol.iterator): ?]
##### 6. 尾調用優化
> 尾調用就是指某個函數的最後一步是調用另一個函數,只在嚴格模式下開啟。
"use strict";
function doSomething(){
//優化後,立即返回結果
return doSomethingElse();
}
function doSomething2(){
//無法優化,無返回
doSomethingElse();
}
> 非嚴格模式下實現尾遞歸優化,用“循環” 替換 “遞歸”
function sum(x,y){
if(y > 0){
return sum( x + 1,y - 1);
} else {
return x;
}
}
sum(1,1000000);// Uncaught RangeError: Maximum call stack size exceeded(...)
//用蹦床函數可以將遞歸執行轉為循環執行
function trampoline(f){
while(f && f instanceof Function){
f = f();
}
return f;
}
//返回一個函數,然後執行該函數,而不是在函數裏調用函數,避免遞歸,消除調用棧過大問題
### 四、數組的擴展
值得摘錄的有以下幾點:
##### 1. 擴展運算符(...)
擴展運算符背後調用的是遍歷器接口(Symbol.iterator),如果一個對象沒有部署該接口就無法轉換
> 替代數組的 Apply方法
//Es5 的寫法
function f(x,y,z){}
var args = [1,2,3];
f.apply(null,args);
//Es6 的寫法
function f(x,y,z){}
var args = [1,2,3];
f(...args);
> 合並數組
Es5 合並數組
var arr1 = [1,2];
var arr2 = [3,4];
var arr3 = [5];
arr1.concat(arr2,arr3);
Es6 合並數組
[...arr1,...arr2,...arr3];
> 能夠識別 32 位的 Unicode 字符的取字符串長度的方法
function length(str){
return [...str].length;
}
length(‘x\uD83D\uDE80y‘); // 3
##### 3. Array.from()方法,用於將類似數組對象和可遍歷對象(包括Set和Map結構)轉為真正的數組
Array.from()方法除了支持遍歷器接口轉換外,還支持類數組對象(類數組對象的本質就是有Length屬性)
Array.from({length:3});
// [undefined,undefined,undefined]
> 映射轉換,Array.from()的第二個參數用來遍歷類數組對象並返回
translate() {
return Array.from(arguments, (value) => value + 1);
}
console.log(NewArray.translate(1,2,3)); // [2,3,4]
##### 4. 為所有數組添加新的方法
> Array.of(),為了彌補數組構造函數Array()的不足
Array.of(3,11,8); // [3,11,8]
Array.of(undefined); // [undefined] , 通過Vue 顯示到頁面則為 [null]
Array(3); // [,,]
> copyWithin(),把數組內部指定位置成員復制到其他位置(會覆蓋其他成員)
//將3號位復制到0號位
[1,2,3,4,5].copyWithin(0,3,4); //[ 4, 2, 3, 4, 5 ]
// -2相當於3號位,-1相當於4號位
[1,2,3,4,5].copyWithin(0,-2,-1); //[ 4, 2, 3, 4, 5 ]
> find(),返回符合條件的第一個(可能有多個)成員,如果沒有就返回undefined
testFind(){ // 返回 3
return [1,2,3,4,5].find((value,index,arr)=>{
return value > 2;
})
}
> findIndex(),返回第一個符合條件的成員的位置,如果沒有就返回 -1
testFindIndex(){ // 返回 -1
return [1,2,3,4,5].findIndex((value,index,arr)=>{
return value > 6;
})
}
> fill(),填充一個數組,接受第二第三個參數(起始位置和結束位置)
testFill(){
console.log([‘a‘,‘b‘,‘c‘].fill(8,1,2)); // ["a", 8, "c"]
return new Array(3).fill(8); //[ 8, 8, 8 ]
}
> includes(),返回一個布爾值,表示某個數組是否包含給定的值,它與indexOf 比起來更加直觀,並且可以判斷NaN的情況
testIncludes(){
return [1,2,NaN].includes(NaN); // true
}
> entries(),keys(),values()方法,它們都返回一個遍歷器對象
testEntries(){
for(let [key,value] of [‘a‘,‘b‘,‘c‘].entries()){
console.log(key,value); // 0 "a" 1 "b" 2 "c"
}
let letter = [‘a‘,‘b‘,‘c‘];
//手動調用遍歷器對象的Next方法進行遍歷
let entries = letter.entries();
console.log(entries.next().value); //[0, "a"]
console.log(entries.next().value); //[1, "b"]
console.log(entries.next().value); //[2, "c"]
}
### 五、對象的擴展
ECMAScript6 中,為了使某些任務更易完成,在全局Object 對象上引入了一些新方法
值得摘錄的有以下幾點:
##### 1. 可計算屬性名
let suffix = " name";
var person = {
["first" + suffix]: "Nicholas", // Es5 版本,這裏的名稱是不可以計算的
["last" + suffix]: "Zakas",
}
console.log(person["first name"]); // "Nicholas"
console.log(person["last name"]); // "Zakas"
##### 2. Object.is(),彌補全等(===)運算符的特殊情況判斷不一致
testObjectIs(){
console.log(+0 == -0); // true
console.log(+0 === -0); // true
console.log(Object.is(+0 , -0)); // false
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN , NaN)); // true
}
##### 3. Object.assign(),只會復制對象自身可枚舉屬性,忽略enumerable為false的屬性
> 多個對象復制具有同名屬性,排位靠後的源對象會覆蓋排位靠前的
testObjectAssign(){
let receiver = {};
Object.assign(receiver,{
type:‘girl‘,
name:‘superman‘,
},{
type:‘boy‘,
})
return receiver.type + " : " + receiver.name; // boy : superman
}
> 對象淺復制(源對象某個屬性是對象,只復制這個對象的引用)
let target = { a: { b: ‘c‘, d: ‘e‘ } };
let source = { a: { b: ‘hello‘ } }
console.log(Object.assign(target, source)); // {a: {b:‘hello‘}}
// a屬性被整體覆蓋掉,不會得到 {a : {b:‘hello‘,d:‘e‘}} 的結果
##### 3. Object.values()
> 只返回對象自身可遍歷屬性
testObjectValues() { // p 的屬性描述對象的 enumerable 默認是 false
var obj = Object.create({}, { p: { value: 42 } });
return Object.values(obj); // []
}
> Object.values 會過濾屬性名為Symbol值的屬性
console.log(Object.values({ [Symbol()]: 123, any: ‘abc‘ })); // [‘abc‘]
##### 3. Object.entries()
> 轉換對象為真正的Map結構
testObjectEntries(){
let obj = { a: ‘bar‘, b: 23 };
let map = new Map(Object.entries(obj));
console.log(map.get(‘a‘)); // bar
}
### 六、集合(Set、Map)
Es6 中的Set和Map核心思想跟Java中的Set和Map類似,Set集合成員是唯一的,沒有重復,Set本身是構造函數用來生成Set數據結構;Map類型是一種存儲著許多鍵值對的有序列表,它的鍵名的判斷是通過Object.is()方法來實現的(Set也是通過這個方法來判斷兩個值是否一致),所以 5 和字符串"5"會被判定為兩種類型。
值得摘錄的有以下幾點:
##### 1. Set
> 添加元素用add()方法,刪除用delete()方法,判斷存在用has(),清空用clear()
testSet() {
let set = new Set();
set.add(5);
set.add(‘5‘);
console.log(set.has(5)); // true
set.delete(5);
console.log(set.has(5)); // false
console.log(set.size); // 1
set.clear();
console.log(set.has(‘5‘)); // false
console.log(set.size); // 0
}
> 數組去重
testArrayUniq(){
let set = new Set([1,2,3,3,3,3,4,4,4,4,5]);
let arr = [...set];
console.log(arr); //[ 1, 2, 3, 4, 5 ]
return arr; //[ 1, 2, 3, 4, 5 ]
}
> 改變原來的Set結構
changeSet(){
let set = new Set([1, 2, 3]);
//方法二
set = new Set([...set].map((val) => val * 2));
//方法二
set = new Set(Array.from(set, val => val * 2));
return set; // [ 4, 8, 12 ]
}
##### 2. Map
Map結構提供了“值-值”對應,而Object結構提供了“字符串-值”對應,Map結構是一種更加完善的Hash結構實現
> 設置值set(),獲取值get(),判斷存在has(),刪除delete(),清空用clear(),多次對同一個鍵賦值,後面覆蓋前面
testMap(){
const m = new Map();
const o = {p:‘hello uct‘};
m.set(o,‘content‘);
m.set(o,‘new content‘)
console.log(m.get(o)); // new content
console.log(m.has(o)); // true
m.delete(o);
console.log(m.has(o)); // false
}
> Map 和 對象互相轉換
//Map轉為對象
strMapToObj(strMap){//Map to Object
let obj = Object.create(null);
for(let [k,v] of strMap){
obj[k] = v;
}
return obj;
}
//對象轉為Map
objToStrMap(obj){// Object to Map
let strMap = new Map();
for(let k of Object.keys(obj)){
strMap.set(k,obj[k]);
}
return strMap;
}
##### 3. WeakMap
WeakMap只接受對象作為鍵名(Null除外)
> WeakMap 應用的典型場景就是以DOM節點作為鍵名的場景
const listener = new WeakMap();
listener.set(element1,handler1);
listener.set(element2,handler2);
element1.addEventListener(‘click‘,listener.get(element1),false);
element2.addEventListener(‘click‘,listener.get(element2),false);
//一旦DOM對象消失,與它綁定的監聽函數也會自動消失
> 部署私有屬性
const _counter = new WeakMap();
const _action = new WeakMap();
class Countdown {
constructor(counter, action) {
_counter.set(this, counter);//weakmap的私有屬性
_action.set(this, action); //weakmap的私有屬性
}
dec() {
let counter = _counter.get(this);
if (counter < 1) return;
counter--;
console.log(counter);
_counter.set(this, counter);
if (counter === 0) {
_action.get(this)();
}
}
}
export default Countdown;
### 結語
*本來覺得沒有必要寫這個筆記,但是,看和寫真的是兩回事。書中的例子大都是抽象化的,也就是為了讓大家看起來直觀,去掉了上下文,有些還有錯。自己動手寫的話(運用實例),印象會非常深刻,在真實開發環境中會想到去用它。筆記的下篇已經在寫了,相對上篇,我更期待下篇,NSL...*
### 參考鏈接
[ECMAScript 6 入門](http://es6.ruanyifeng.com/)
[UNDERSTANDING ES6 英文原版](https://leanpub.com/understandinges6/read)
《ES標準入門》&《UNDERSTANDING ECMACHRIPT 6》 讀書摘錄筆記(上)