1. let
1. let只在當前代碼塊內有效。
for(let i=0;i<arr.length;i++){
.....
}
console.log(i) // i is not defined
2. let不存在變量提升
3. 暫時性死區
var temp=123;
if(true){
let temp=4556;
//內部temp相當於一個局部變量,在聲明之前,該變量不可使用。在語法上稱爲“暫時性死區”
}
console.log(temp) // 1234. 不允許重複聲明
let 不允許在相同作用域({})內重複聲明一個變量。
ES6允許塊級作用域任意嵌套,且外層作用域無法讀取內層作用域的變量。
5. ES6規定,塊級作用域中,函數聲明語句類似let,塊級作用域外不可引用
2. const
const聲明是一個只讀的常量,不能改變
只在聲明所在的塊級作用域內有效
notice:
var 命令和function命令聲明的全局變量依舊是全局對象的屬性,let,const命令聲明的全局變量不再屬於全局對象的屬性。
3. 變量解構賦值
- 數組解構賦值: var [a,b,c]=[1,2,3]
- 對象解構賦值:
var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"- 字符串解構賦值
- 函數參數解構賦值
用途
- 交換變量值 eg.[x,y]=[y,x]
- 從函數返回多個值。
-function example(){
return [1,2,3];
}
var [a,b,c]=example();
- 函數參數的定義
-// 參數是一組有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
- 提取JSON數據
var jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
- 函數參數的默認值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
}) {
// ... do stuff
};遍歷Map結構
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world輸入模塊的指定方法:
const { SourceMapConsumer, SourceNode } = require("source-map");
4. 字符串的擴展
- codePointAt([index]):返回對應位置字符的碼點
- String.fromCodePoint([unicode]):用於從碼點返回對應字符。
- at():返回字符串給定位置的字符。
- for….of: 新增字符串遍歷接口
- includes(), startsWith(),endsWith(): 返回布爾值。
- repeat(n): 返回重複n次的字符串
padStart(), padEnd(): ES7推出,頭部、尾部補全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'模板字符串:(“),模板字符串中嵌入變量,需要將變量名寫在${}之中。
- String.raw()
5. 正則的擴展
6. 數值的擴展
- Number.isFinite(), Number.isNaN(): 只對數值數值有效,否則一律返回false
- Number.parseInt(), Number.parseFloat();
- Number.isInteger(): 3和3.0爲同一個值。
- Number.EPSILON,新增一個極小常量。
- Math對象的擴展
- Math.trunc(): 去除一個數的小數部分,返回整數部分。
- Math.sign(): 用來判斷一個數是正數,負數,零。
參數爲正數,返回+1;
參數爲負數,返回-1;
參數爲0,返回0;
參數爲-0,返回-0;
其他值,返回NaN。
7. 數組的擴展
1 . Array.from(arrlike,[func],[context]): 將類數組和可遍歷的對象轉換爲數組。功能類似於ES5:[].slice.call(arraylike)。第二個參數,類似於map方法,將處理後的值放入返回的數組。第三個參數,傳入this的環境。
2 . 擴展運算符:(…)也可以將某些數據轉換爲數組。eg. function foo() {
var args = [...arguments];
}
3 . Array.of(): 將一組值轉換爲數組。Array.of(3, 11, 8) // [3,11,8]
4 . copyWithin(target, start = 0, end = this.length):
target(必需):從該位置開始替換數據。
start(可選):從該位置開始讀取數據,默認爲0。如果爲負值,表示倒數。
end(可選):到該位置前停止讀取數據,默認等於數組長度。如果爲負值,表示倒數。
5 . find(): 用於找到第一個符合條件的數組成員。
6 . findIndex(): 返回第一個符合條件的數組成員的位置
7 . fill(): 使用給定值,填充一個數組。
8 . 數組實例的:entries(),keys(),values()
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
9 . includes(): Array.prototype.includes返回一個布爾值。
8. 函數的擴展
1 . ES6允許爲函數的參數設置默認值,即直接寫在參數定義的後面。eg. function log(x, y = 'World') {
console.log(x, y);
}
2.(…): 可以將一個數組轉爲逗號分隔的參數序列。
3 . name屬性:返回該函數的函數名。
4 . 箭頭函數
如果箭頭函數的代碼塊部分多於一條語句,需要用大括號括起來,並使用return返回。
1. 函數體內的this對象,是定義時所在的對象,不是使用時所在的對象。
2. 不可以當作構造函數,即不能使用new命令,否則報錯。
3. 不可以使用arguments對象,該對象在函數體內不存在。
4. 不可以使用yield命令。
5 . 函數綁定
函數綁定運算符:(::),左邊是對象,右邊爲函數,運算符會自動將左邊對象作爲上下文環境。
6 . 尾調用優化,尾遞歸
9. 對象的擴展
1 . 屬性簡潔表示:
- ES6允許在對象中,只寫屬性名,不寫屬性值,這時屬性值等於屬性名所代表的變量。eg.
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}- 方法也可以簡寫: eg.
var o={method(){return 'hello!'}}
- ES6允許字面量定義對象,使用變量作爲屬性名。eg:
let obj = {[propKey]: true, ['a' + 'bc']: 123
};- 屬性名表達式與簡潔表示法不能同時使用。
2 . Object.is(): 比較兩個值是否嚴格相等,基本與“===”相同,但+0不等於-0,二是NaN等於自身。
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
3 . Object.assign(): 用於對象的合併,只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉屬性。
var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
notes:
- Object.assign是淺拷貝,即如果源對象某個屬性的值是對象,那麼目標對象得到的是對這個對象的引用。如果源對象發生變化,目標對象的屬性也會改變。
- Object.assign還能用來處理數組,但會把數組視爲對象。eg:
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
4 . 屬性遍歷:
- for…in
- Object.keys(obj): 返回自身所有可枚舉屬性的數組
- Object.getOwnPropertyNames(obj): 返回自身的所有屬性的數組。
- Object.getOwnPropertySymbols(obj):返回一個數組,包含自身所有symbol屬性。
- Refletc.ownKeys(obj)
- __proto__屬性: 讀取或設置當前prototype對象。可以用:Object.setPrototypeOf()(寫操作)、Object.getPrototypeOf()(讀操作)、Object.create()(生成操作)代替
- Object.setPrototypeOf():設置對象的prototype對象。
- Object.getPrototypeOf():讀取
- Object.values(), Object.entries(),Object.keys
5 . 對象的擴展運算符
- Rest解構賦值(…): 用於從一個對象取值,將所有可遍歷但未讀取的屬性,分配到對象上。
eg:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }- 擴展運算符(…): 用於取出參數對象的所有可遍歷屬性,拷貝到當前對象中。
10 . Symbol
原始數據類型,表示獨一無二的值,保證對象的屬性獨一無二。
Symbol作爲屬性名,該屬性不會出現在for…in、for…of循環中,也不會被Object.keys()、Object.getOwnPropertyNames()返回。但是,它也不是私有屬性,有一個Object.getOwnPropertySymbols方法,可以獲取指定對象的所有Symbol屬性名。
Object.getOwnPropertySymbols方法返回一個數組,成員是當前對象的所有用作屬性名的Symbol值。
11 . Set和Map數據結構
set
類似於數組,成員值都是唯一的,無重複。
var s=new Set();
[2, 3, 5, 4, 5, 2, 2].map(x => s.add(x));
log([...s])// [1, 2, 3]
log(Array.from(s))//[1, 2, 3]
log(s)//Set(3) {1, 2, 3}
1 . set 函數可以接受一個數組或類數組作爲對象,轉換爲set數據。
var set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
> 向set加入值,不會發生類型轉換。5和"5"是不同值,但NaN等於NaN。
2 . set實例屬性和方法:
- Set.prototype.constructor:構造函數,默認就是Set函數。
- Set.prototype.size:返回Set實例的成員總數。
- 實例方法:
add(value):添加某個值,返回set結構本身
delete(value):刪除某個值,返回布爾值,表示是否刪除成功。
has(value): 返回一個布爾值,表示是否爲Set成員。
clear():清除所有成員,沒有返回值。
3 . 遍歷操作:
keys(),values(),entries(),forEach()
由於Set結構沒有鍵名,只有鍵值(或者說鍵名和鍵值是同一個值),所以key方法和value方法的行爲完全一致。
let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.values()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.entries()) {
console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]
Set結構的實例默認可遍歷,它的默認遍歷器生成函數就是它的values方法。這意味着,可以省略values方法,直接用for…of循環遍歷Set。
let set = new Set(['red', 'green', 'blue']);
for (let x of set) {
console.log(x);
}
// red
// green
// blue
WeakSet
weakSet與Set類似,也是不重複的值的集合,區別:
1. WeakSet成員只能是對象
2. WeakSet對象都是弱引用,即垃圾回收機制不考慮WeakSet對該對象的引用,如果其他對象不再引用這個對象,那麼垃圾回收機制將自動回收該對象所佔內存。這意味着無法引用WeakSet的成員,因此WeakSet不可遍歷。
var ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set
WeakSet可以接受一個數組或類似數組的對象作爲參數。該數組的所有成員,都會自動成爲WeakSet實例對象的成員。因此:數組的成員只能是對象。
原型方法:
WeakSet.prototype.add(value):向WeakSet實例添加一個新成員。
WeakSet.prototype.delete(value):清除WeakSet實例的指定成員。
WeakSet.prototype.has(value):返回一個布爾值,表示某個值是否在WeakSet實例之中。
Map
Map類似於對象,也是鍵值對的集合,但是“鍵”不限於字符串,各種類型的值都可以當鍵。
1 . 接受對象作爲鍵值
var m=new Map();
var o={p:"hello world"};
m.set(o,"content");
m.get(o);// "content"
m.has(o) // true
m.delete(o) // true
m.has(o) // false
2 . 接受數組作爲參數,數組成員是一個個表示鍵值對的數組。
var map = new Map([
['name', '張三'],
['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "張三"
map.has('title') // true
map.get('title') // "Author"
只有對同一個對象的引用,Map結構纔將其視爲同一個鍵。
var map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
實例屬性和操作方法:
(1)size屬性
(2)set(key, value)
(3)get(key)
(4)has(key)
(5)delete(key)
(6)clear()
遍歷方法:
keys():返回鍵名的遍歷器。
values():返回鍵值的遍歷器。
entries():返回所有成員的遍歷器。
forEach():遍歷Map的所有成員。
12 . Iterator和for…of循環
遍歷器(Iterator)是一種接口,爲各種不同數據結構提供統一訪問機制。任何數據只要部署Iterator接口,就可以完成遍歷操作。
作用:
1. 提供統一的訪問接口
2. 使數據結構的成員按照某種次序排列
3. 創造了新的遍歷命令for…of循環,Iterator接口主要供for…of消費。
13 . Generator函數
function * foo(x, y) { ··· }
Generator函數是一個普通函數,有兩個特徵:
1. function關鍵字和函數名之間有一個*號
2. 函數體內部,使用yield語句,定義不同內部狀態。如果有多條yield語句,可以遍歷然後輸出
Generator函數調用同樣加圓括號,但是調用後並不執行,必須調用遍歷器對象的next方法,才執行,遇到yield語句,暫停,直到遇到下個next方法恢復執行,一直執行到return語句,遍歷結束,done屬性爲true.
1 . yield語句
Generator函數也可以省略yield,即變成一個單純的暫緩執行函數。
function* f() {
console.log('執行了!')
}
var generator = f();
setTimeout(function () {
generator.next()
}, 2000);
- yield語句不能再普通函數中調用。
- yield語句如果用在一個表達式之中,必須放在圓括號裏面。
for…of循環可以自動遍歷Generator函數生成的Iterator對象,此時不再需要調用next方法。
14 . Promise
Promise是一個對象,可以獲取異步操作的消息。
Promise狀態:
pending, resolved, rejected
只有異步操作的結果,可以決定當前是哪種狀態,任何其他操作都無法改變這個狀態。
基本用法
var promise=new Promise(function(resolve,reject){
//...some code
if(/*異步操作成功*/){
resolve(value)
}else{
reject(error)
}
})
Promise 構造函數接受一個函數作爲參數,該函數兩個參數分別是resolve
和reject
,是兩個函數。由js引擎提供。
resolve
函數作用:將Promise對象的狀態從“pending”變“resolved”,在異步操作成功時調用,並將異步操作結果傳遞出去。
reject
函數作用:將狀態由“pending”變“reject”,失敗時調用,並將錯誤作爲參數傳遞出去。
Promise實例生成後,可以用then方法分別制定resolved,reject狀態的回調函數。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
實例:
var proTimer=function(){
return new Promise(function(resolve,reject){
setTimeout(function(){
if(test>100){
resolve("成功")
}else{
reject("失敗")
}
},1200)
})};
//proTimer異步函數執行後,promise狀態改變,會立即出發then方法綁定的回調函數。
proTimer().then(function(value){
log(value)
},function(err){
log(err)
});
Promise.prototype.then()
then方法返回的是一個新的promise實例,因此可以採用鏈式寫法,then後面再調用then, 第一個回調函數完成後,會將返回結果作爲參數傳遞給第二個then回調函數。
Promise.prototype.catch()
Promise.prototype.catch方法是.then(null, rejection)的別名,用於指定發生錯誤時的回調函數。
getJSON("/posts.json").then(function(posts) {
// ...
}).catch(function(error) {
// 處理 getJSON 和 前一個回調函數運行時發生的錯誤
console.log('發生錯誤!', error);
});
一般來說,不要在then方法裏面定義Reject狀態的回調函數(即then的第二個參數),總是使用catch方法。
跟傳統的try/catch代碼塊不同的是,如果沒有使用catch方法指定錯誤處理的回調函數,Promise對象拋出的錯誤不會傳遞到外層代碼,即不會有任何反應。但chrome瀏覽器不遵守這條規定,會拋出錯誤。
promise.all()
用於將多個Promise實例,包裝成一個新的promise實例
var p= Promise.all([p1,p2,p3]);
Promise.all方法的參數必須有iterator接口,且返回的每個成員都是promise實例。
p的狀態由p1、p2、p3決定,分成兩種情況。
(1)只有p1、p2、p3的狀態都變成fulfilled,p的狀態纔會變成fulfilled,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回調函數。
(2)只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。
Promise.race()
Promise.race
同樣將多個promise實例包裝成一個新實例。
var p=Promise.race([p1,p2,p3])
不同的是,只要任一個實例率先改變,p的狀態就跟着改變。率先改變的promise實例的返回值就傳遞給p的回調函數。
Promise.resolve()
將現有對象轉換爲Promise對象。
Promise.resolve("foo")
//等價於
new Promise(resolve=>resolve("foo"))
Promise.resolve方法參數分爲四種情況:
1. 參數是一個promise實例:那麼不做任何修改,返回這個實例。
2. 參數是一個thenable對象,指具有then方法的對象。
let thenable={
then:function(resolve,reject){...
.)}
Promise.resolve會將這個對象轉換爲promise對象,然後立即執行thenable對象的then方法。
3. 參數不是具有then方法的對象,或者不是對象。
promise.resolve返回一個新的promise對象,狀態爲resolved.
var p = Promise.resolve('Hello');
p.then(function (s){
console.log(s)
});
// Hello
4 . 不帶參數:直接返回一個resolved狀態的promise對象。立即resolve的promise對象,是在本輪“事件循環”結束時,setTimeout是在下一次事件循環開始時。
Promise.reject()
Promise.reject(reason)也會返回一個promise實例,實例狀態爲rejected.
部署done(), finally()方法
done()
保證拋出任何可能出現的錯誤。
Promise.prototype.done=function(onFullfilled,onRejected){
this.then(onFullfilled,onRejected)
.catch(function(reason){
setTimeout(()=>{throw reason},0)
})
}
finally()
finally方法用於指定不管promise對象最後狀態如何,都會執行的操作,接受一個普通的回調函數作爲參數,該函數不管怎樣都必須執行。
Promise.prototype.finally=function(callback){
let P=this.constructor;
return this.then(
value => P.resolve(callback()).then(()=>value),
reason=>P.resolve(callback()).then(()=>{throw reason})
)
}
15 . 異步操作和Async函數
異步編程的實現:
回調函數:
fs.readFile('/etc/passwd', function (err, data) {
if (err) throw err;
console.log(data);
});
Promise:將回調函數的嵌套修改成鏈式調用。
Generator函數
協程:多個線程相互協作,完成異步任務
運行流程如下:
第一步,協程A開始執行。
第二步,協程A執行到一半,進入暫停,執行權轉移到協程B。
第三步,(一段時間後)協程B交還執行權。
第四步,協程A恢復執行。
協程A就是異步任務,它分兩段或多段執行
寫法如下:
function * asyncJob(){
//...其他代碼
var f=yield readFile(fileA);//執行到此處,執行權轉讓出去,等到執行權返回後,再從這繼續往後執行
//...其他代碼
}
Generator函數調用next()方法可以繼續執行任務。
Generator函數的數據交換和錯誤處理:
next():返回的值是Generator函數向外輸出的數據,next()還可以接受參數,進而傳入到Generator函數,作爲上個階段任務的返回結果。
function* gen(x){
var y = yield x + 2;
return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }
Generator函數內部還可以部署錯誤處理代碼,捕獲函數體外拋出的錯誤:
function* gen(x){
try {
var y = yield x + 2;
} catch (e){
console.log(e);
}
return y;
}
var g = gen(1);
g.next();
g.throw('出錯了');
// 出錯了
異步任務的封裝:
var fetch=require("node-fetch");
function * gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}
var g=gen();
var result= g.next();
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data)
})
Thunk函數的含義
參數求值策略:
1. 傳值調用:進入函數體之前,就計算好參數的值
2. 傳名調用:進入函數體之後,用到該參數的時候,計算該參數的值。
傳名調用的實現,即將參數放到一個臨時函數中,再將這個臨時函數傳入函數體,這個臨時函數成爲Thunk函數。
function f(m){
return m * 2;
}
f(x + 5);
// 等同於
var thunk = function () {
return x + 5;
};
function f(thunk){
return thunk() * 2;
}
JS中也是傳值調用,但是它的thunk函數替換的不是表達式,而是多參數函數,將其替換成單參數版本,且只接受回調函數作爲參數。
Async函數
1. async函數返回一個promise對象
async函數內部,return語句返回的值,會成爲then方法回調函數的參數。
2. async函數返回Promise對象,必須要等到內部所有await命令的promise對象執行完,纔會發生狀態改變。
3. 正常情況下,await命令後面是一個promise對象,如果不是,會調用Promise.resolve()轉換成promise對象。
await命令後面的Promise對象如果變爲reject狀態,reject的參數會被catch方法的回調函數接收到。
只要一個await的promise變爲reject,那麼整個async函數都會中斷執行。
eg.
async function f() {
await Promise.reject('出錯了');
await Promise.resolve('hello world'); // 不會執行
}
爲避免這個問題,兩種解決方法:
1. 放在try…catch結構裏
async function f() {
try {
await Promise.reject('出錯了');
} catch(e) {
}
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// hello world
- await後面promise對象再跟一個catch
async function f() {
await Promise.reject('出錯了')
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// 出錯了
// hello world如果有多個await命令,可以統一放在try…catch結構中
4 . 如果await後面的異步操作出錯,那麼等同於async函數返回的promise對象被reject.
注意點
- 最好把await命令放在try…catch代碼塊中
- 多個await命令後面的異步操作,如果不存在繼發關係,最好讓它們同時觸發。
繼發:
let foo = await getFoo();
let bar = await getBar();
同時觸發:
// 寫法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 寫法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
3 . await只能用在async函數中,用在普通函數中會報錯,例如forEach裏不能用await.可以使用for循環。
16. Class類
ES6引入class概念,通過class關鍵字定義類。
//定義類
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {//定義在prototype原型上的方法
return '(' + this.x + ', ' + this.y + ')';
}
}
定義類的方法的時候,不需要function關鍵字,直接定義函數就可以,方法之間不需要都好分隔,否則會報錯。
使用類,也是用new命令,跟構造函數用法一致。
可以使用Object.assign()一次性向類添加多個原型方法:
class Point{
constructor(){
//...
}
}
Object.assign(Point.prototype,{
toString(){},
toValue(){}
})
類內部定義的所有方法,都是不可枚舉的。
- constructor方法:生成實例自動調用該方法,如果沒有顯示定義,會默認添加一個空的constructor(){}, 默認返回實例對象,也可以改寫。
- 不存在變量提升。
- 類也可以用表達式的形式定義。
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
//使用表達式定義了一個類。需要注意的是,這個類的名字是MyClass而不是Me,Me只在Class的內部代碼可用,指代當前類。如果內部沒有用到Me,可以省略Me,即:
const MyClass=class {//....}
4 . 私有方法:
es6不提供私有方法,可以在模塊外定義私有方法,然後模塊內部調用bar.call(this,baz),這就使得bar成爲當前模塊的私有方法。
5 . this指向:默認指向類的實例,