ECMAScript 6學習
es6新特性
let、const和var的區別⭐
1. 塊級作用域{}
Es5中作用域有:全域性作用域、函式作用域,沒有塊級作用域的概念
Es6中新增塊級作用域。塊級作用域用{}包括,if和for語句裡面的{}也屬於塊作用域
2. var沒有塊的概念,可以跨塊訪問,不能跨函式訪問
3. let只能在塊作用域訪問,不能跨塊或跨函式訪問
4. const用來定義常量,使用時必須初始化(即必須賦值,只能在塊作用域訪問,且不能更改)
const定義的物件屬性是否可以改變?因為物件是引用型別,物件中儲存的僅是物件的指標,const保證指標不發生改變,修改物件屬性不會改變物件指標
陣列方法⭐
forEach()、some()、filter()、map()、reduce()、every()、find()
forEach()
var arr = [1, 2, 3];
arr.forEach(function (value, index, array) {
console.log('每個陣列元素' + value);
console.log('每個陣列元素的索引號' + index);
console.log('陣列本身' + array);
})
some()
// 只要有一個滿足就行 var arr = [10,20,30,40,50]; var flag = arr.some(function(value){ return value > 20; // 在 some 裡面遇到 return true 就會終止遍歷 效率更高 });// true
every()
// 要所有的滿足才可以
var arr = [10,20,30,40,50];
let res = arr.every(item => item > 20) // false
filter()
var arr = [12, 66, 4, 55, 22, 11];
var newArr = arr.filter(function (value, index) {
return value % 2 === 0; // filter 裡面 return 不會終止迭代,要有返回值,返回一個新陣列
});
// [66,55,22]
map()
var numbers = [1,2,3] var double = numbers.map(number => number * 2) // 要有返回值,返回一個新陣列 console.log(double) // [2,4,6]
reduce()
// reduce(function(sum,number){...},0)要有兩個引數,第一個引數一定要初始化
// 代替map做一些簡單的運算
// 將一個物件陣列中的某些屬性的值抽出來,組成一個新的陣列
var arr = [1,2,3]
var res = arr.reduce((sum,number)=>{
return sum + number
},3) // 4,5,6
find()
// 只會找到第一個符合的資料,找到之後就會直接返回
let aim = 1
let arr = [1,2,3]
let res = arr.find(item => item === aim)
for...of迴圈
for...of
迴圈是最新新增到 JavaScript 迴圈系列中的迴圈。
它結合了其兄弟迴圈形式 for
迴圈和 for...in
迴圈的優勢,可以迴圈任何可迭代(也就是遵守可迭代協議)型別的資料,可以隨時停止或退出迴圈。預設情況下,包含以下資料型別:String
、Array
、Map
和 Set
。預設情況下,物件不可迭代。
for...of遍歷的是鍵值,for...in遍歷的是鍵名
for...of不能對屬性值進行修改,forEach()可以
不用擔心向物件中新增新的屬性。for...of 迴圈將只迴圈訪問物件中的值。
Array.prototype.decimalfy = function() {
for (i = 0; i < this.length; i++) {
this[i] = this[i].toFixed(2);
}
};
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const digit of digits) {
console.log(digit);
}
rest引數
ES6引入rest引數,用於獲取函式的實參,用來代替arguments物件,它不僅將額外的引數表示為陣列,還解決了arguments物件的許多問題。
arguments物件用於訪問未知或可變的函式引數,即使arguments使用length屬性和方括號,它不是一個真正的JavaScript陣列。arguments物件不能使用其他JavaScript陣列方法,如pop,push,slice等。
你可以將rest引數定義為…theArgs或… args。如果最後命名的函式引數以…(三個點)作為字首,那麼它將成為函式的rest引數。
function add(...theArgs){
var result = 0;
for(let i=0;i<theArgs.length;i++){
result = result + theArgs[i];
}
return result;
}
var r = add(6,9,3,2);
console.log(r);
rest引數是JavaScript陣列,可以對rest引數theArgs執行諸如push,pop等操作
function add(...theArgs){
theArgs.push(10);
var result = 0;
for(let i=0;i<theArgs.length;i++){
result = result + theArgs[i];
}
var lastItem = theArgs.pop();
console.log(lastItem);
return result;
}
JavaScript函式的rest引數也可以與其他引數一起工作
function add(num1, num2, ...theArgs){ // rest引數必須是最後一個正式引數。
console.log(num1);
console.log(num2);
console.log(theArgs.length);
}
var r = add(6,9,3,2); // 前兩個引數不會成為rest引數陣列的一部分
箭頭函式⭐
使用方法
() => {}
和普通函式的區別
① 普通函式可以是函式宣告或者函式表示式, 但是箭頭函式始終都是表示式, 全程是箭頭函式表示式, 因此僅在表示式有效時才能使用
② 普通函式的this指向呼叫其函式的物件,而箭頭函式的this始終指向函式宣告時所在作用域下的this的值,無法被call改變
③ 箭頭函式不能作為建構函式例項化物件
④ 箭頭函式不能使用arguments變數,但是可以使用...rest
模組化es6⭐
ES6模組化規範中定義
② 匯入模組成員使用 import 關鍵字
③ 暴露模組成員使用 export 關鍵字
CommonJS
② 模組成員匯出:(ma zou) module.exports 和 exports
③ 模組成員匯入:require('模組識別符號')
和CommonJs的異同
異:
① CommonJS 模組是執行時載入,ES6 模組是編譯時輸出介面
執行時載入: CommonJS 模組就是物件;即在輸入時是先載入整個模組,生成一個物件,然後再從這個物件上面讀取方法,這種載入稱為“執行時載入”。
編譯時載入: ES6 模組不是物件,即在import時可以指定載入某個輸出值,而不是載入整個模組,這種載入稱為“編譯時載入”
② CommonJS 模組輸出的是一個值的拷貝,ES6 模組輸出的是值的引用
CommonJS 是對模組的淺拷貝,ES6 Module 是對模組的引用,即ES6 Module只存只讀,不能改變其值,具體點就是指標指向不能變,類似 const。
同:
CommonJS和ES6 Module都可以對引入的物件進行賦值,即對物件內部屬性的值進行改變。
模板字串⭐
在ES6之前,將字串連線到一起的方法是+
或者concat()
方法
模板字串本質上是包含嵌入式表示式的字串字面量.
模板字面量用倒引號 ( `` )
(而不是單引號 ( '' )
或雙引號( "" )
)表示,可以包含用 ${expression}
表示的佔位符
類class⭐
ES6中添加了對類的支援,引入了class關鍵字。JS本身就是面向物件,ES6中提供的類實際上只是JS原型模式包裝。
以前編寫一個建構函式(類)
function Pad(color){
this.color = color;
}
現在的寫法跟Java更接近了
class Iphone{
constructor(color, size){
this.color = color;
this.size = size;
}
playgame(){
//.............
}
toString(){
return `這臺手機的顏色是${this.color} 螢幕大小是${this.size}`;
}
}
我們定義了一個類,名字叫Iphone
通過類生成一個例項:
var iphone = new Iphone("白色", 5);其中constructor被稱之為構造方法,在我們new 一個物件的時候,自動被呼叫不過本質上,JS依然使用了原型來實現,也就是說,這不過是一個新的寫法而已 跟以前的建構函式沒有區別。要注意的是,使用了class來定義類,必須先定義再使用
解構⭐
解構:從陣列和物件提取值並賦值給獨特的變數
陣列解構
const Web = ['html', 'css', 'javascript']
let [tool1, tool2, tool3] = Web
物件解構
const liMing = {
name: 'liMing',
age: '22',
tell: function(){
console.log(`I am liMing`)
}
}
let {name, age, tell} = liMing
物件字面量簡寫法
如果屬性名稱和所分配的變數名稱一樣,那麼就可以從物件屬性中刪掉這些重複的變數名稱
type: type => type
Promise物件⭐
Promise出現的目的是解決Node.js非同步程式設計中回撥地獄的問題。
resolve => .then 成功 reject => .catch 失敗
function p1(){
return new Promise(function(resolve,reject){
// 假如讀取多個檔案
fs.readFile('./1.txt', 'utf-8', (err, doc) => {
if (err) {
reject(err);
} else {
resolve(doc);
}
})
})
}
function p2()....../2.txt
p1().then(r1=>{
console.log(r1);
// return一個promise物件,那麼下一個then當中拿到的結果就是在上一個then裡面return的promise物件的結果
return p2();
})
.then((r2) => {
console.log(r2);
})
// promise 語法無巢狀,更易維護,解決回撥地獄問題
then的第二個引數和catch捕獲錯誤資訊的時候會就近原則,如果是promise內部報錯,reject丟擲錯誤後,then的第二個引數和catch方法都存在的情況下,只有then的第二個引數能捕獲到,如果then的第二個引數不存在,則catch方法會捕獲到。
Promise.resolve('foo')
// 等價於
new Promise(resolve => resolve('foo'))
promise.all()
可以將多個Promise例項包裝成一個新的Promise例項。成功和失敗的返回值是不同的,成功的時候返回的是一個結果陣列,而失敗的時候返回最先被reject失敗狀態的值。
let p1 = new Promise((resolve,reject) => {
resolve("成功了");
})
let p2 = new Promise((resolve,reject) => {
resolve("success");
})
let p3 = new Promise((resolve,reject) => {
reject("fail");
})
Promise.all([p1,p2]).then((result) => {
console.log(result) // ['成功了','success']
}).catch((error) => {
console.log(error)
})
Promise.all([p1,p3,p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 'fail'
})
有些時候我們做一個操作可能得同時
需要不同的介面返回的資料,這時我們就可以使用Promise.all
;
Promise.all獲得的成功結果的數組裡面的資料順序和Promise.all接收到的陣列順序是一致的,即p1的結果在前,即便p1的結果獲取的比p2要晚。
promise.all實現
let promiseAll = (promises) => {
return new Promise((resolve, reject) => {
// 判斷是否為陣列
if (!(promises instanceof Array)) {
// 丟擲錯誤
throw new TypeError('promises must be an Array')
}
let len = promises.length // promise物件陣列長度
let resolveCount = 0 // 當前遍歷到第一個,最後一個時返回正確的陣列
let resolveArr = new Array(len) // 成功輸入的陣列,與遍歷的promise陣列長度一致
for (let i = 0; i < len; i++) {
(function(i){ // 用上閉包更好
promises[i].then(data => {
resolveCount++
resolveArr[i] = data
// 如果都是成功的,只有到最後一個才會返回正確的陣列
if (resolveCount === len) {
return resolve(resolveArr)
}
// 一旦有錯誤就返回該項錯誤,並終止遍歷該promise物件陣列,實現失敗的時候返回最先被reject失敗狀態的值
}).catch(err => {
return reject(err)
})
})(i)
}
})
}
promiseAll([p1, p2, p3]).then(data => {
console.log(data);
}).catch(res => {
console.log(res);
})
promise.race()
Promise.race([p1,p2,p3])裡面哪個結果獲得快,就返回哪個結果,不管結果本身是成功還是失敗狀態。
有時我們比如說有好幾個伺服器的好幾個介面都提供同樣的服務
,我們不知道哪個介面更快,就可以使用Promise.race
,哪個介面的資料先回來我們就用哪個介面的資料。
async/await配合使用
Set集合和Map集合
兩者都集合實現了iterator介面,所以可以使用...擴充套件運算子和for...of
進行遍歷
set:
set是ES6提供的一種新的資料結構,類似於陣列,但是成員的值是唯一的沒有重複的,接受的引數是一個數組 方法有:
add():新增
delete():刪除
size:長度
has():查詢
clear:清除所有
map:
map類似於物件,也是鍵值對的集合, 但是“鍵”的範圍不限於字串,各種型別的值(包括物件)都可以當作鍵 方法有:
set():設定
get():獲取
delete():刪除
has():查詢
clear():清除所有
擴充套件運算子...⭐
用三個連續的點 (...
) 表示,能夠將字面量物件展開為多個元素,可使用者陣列的合併、克隆和將偽陣列轉為真正的陣列(多個dom物件)
函式引數的預設值設定
ES6允許給函式引數賦初始值,可與...擴充套件運算子一起使用
function add(a, b, c=10){ // 具有預設值的引數,一般位置要靠後
return a + b + c
}
console.log(add(1,2,))
Symbol
ES6引入了一種新的原始資料型別Symbol,表示獨一無二的值。它是JavaScript語言的第7種資料型別,是一個類似字串的資料型別l
建立Symbol:
- 通過
let s2 = Symbol('張三')
的方式建立Symbol,'張三’作為Symbol描述,作用相當於註釋,這種方式建立的Symbol,即使傳入的描述一致,但實際返回的值是不同的
// 建立Symbol
let s = Symbol()
console.log(s,typeof s) // Symbol() "symbol"
let s2 = Symbol('張三') // '張三'作為Symbol描述,作用相當於註釋
let s3 = Symbol('張三') // 即使傳入的描述一致,但實際返回的值是不同的
console.log(s2 === s3) // false
-
通過
Symbol.for()
建立Symbol,這種方式建立Symbol,傳入的描述一致,實際返回的值也一致,可以得到唯一的Symbol值// Symbol.for建立Symbol let s4 = Symbol.for('張三') let s5 = Symbol.for('張三') console.log(s4 === s5) // true
迭代器iterator(A te wei te)
迭代器(iterator)是一種介面,為各種不同的資料結構提供統一的訪問機制。任何資料結構只要部署iterator介面,就可以完成遍歷操作
字串API
在ES6中,為字串擴充套件了幾個新的API
- includes(“xxx”):返回布林值,表示是否包含xxx
- startsWith(“xxx”):返回布林值,表示是否以xxx開頭
- endsWith(“xxx”):返回布林值,表示是否以xxx結尾
let str = "Hello Javascript";
console.log(str, "中是否包含 hello ==>", str.includes("hello"));
console.log(str, "中是否包含 hi ==>", str.includes("hi"));
console.log(str, "中是否以 h 開頭==>", str.startsWith("h"));
console.log(str, "中是否以 a 開頭==>", str.includes("a"));
console.log(str, "中是否以 a 結尾==>", str.includes("a"));
console.log(str, "中是否以 t 結尾==>", str.includes("t"));