第八課之提高開發效率的es6以及函式
es6的介紹
2011 年,ECMAScript 5.1 版釋出後(es5),就開始制定 6.0 版了,ECMAScript 2015(簡稱 ES2015),ES6 的第一個版本,在 2015 年 6 月釋出了。因此,ES6 這個詞的原意,就是指 JavaScript 語言的下一個版本,涵蓋了 ES2015、ES2016、ES2017 等等
ES6中包含了許多新的語言特性,它們將使JS變得更加強大,更富表現力。對於很多開發者來說,ES6帶來的新功能涵蓋面很廣,還有很多很便利的功能等(如:箭頭的功能和簡單的字串插值),確實令人興奮。
es6常用語法
let
ES6新增了let命令,用來生命變數。它的用法類似於var,但是所宣告的變數,只在let命令所在的程式碼塊內有效。
變數i是var命令宣告的,在全域性範圍內都有效,所以全域性只有一個變數i。 每一次迴圈,變數i的值都會發生改變,而迴圈內被賦給陣列a的函式內部的console.log(i), 裡面的i指向的就是全域性的i。也就是說,所有陣列a的成員裡面的i, 指向的都是同一個i,導致執行時輸出的是最後一輪的i的值,也就是 10 var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10 閉包 如果使用let,宣告的變數僅在塊級作用域內有效,最後輸出的是 6。 var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
const
const宣告一個只讀的常量,一旦宣告,常量的值就不能改變。
const a = 1;
a = 2; // 報錯
const b = {};
a = {a:1}; // 報錯
const c = {c:1};
c.c = 2; // 不報錯
// 簡單理解,改變物件值,改變陣列索引的值都不會報錯,但是如果直接修改自身數值就會報錯
let與const
1.都不能重複宣告
2.都存在塊級作用域問題
3.只在宣告所在的塊級作用域內有效
開發使用
所有的變數都用let進行定義,所有的常量都是用const進行定義
解構賦值
ES6 允許按照一定模式,從陣列和物件中提取值,對變數進行賦值,這被稱為解構
- 物件結構賦值
// 1.獲取鍵值
let obj ={ name:"abc",age:18 };
// 以前的寫法
let name = obj.name;
let age = obj.age;
//用解構賦值的方式獲取name、age
let { name, age } = obj; //建立了一個變數name,值=obj.name
console.log(name,age); //"abc" 18
// 2.重新命名(比如想要獲取資料的變數和我們已有的變數重名,就需要進行重新命名)
let { name: n, age: a } = obj;
console.log(n,a); //"abc" 18
// 3.解構再解構
let jsonData = {
id: 42,
status: "OK",
data: {list:[],total:1000}
};
let { id, status, data: {list,total} } = jsonData;
console.log(id, status, list,total);
// 42 "OK" [] 1000 不過這個時候就不能訪問到data了
- 陣列解構賦值
// 獲取對應索引下的值
let data= [1,2,3];
// 以前的寫法
let a = data[0];
let b = data[1];
let c = data[2];
// 現在的寫法,如果對不上,值就是undefined
let [a, b, c] = [1, 2, 3];
console.log(a,b,c);
- 字串解構賦值
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
- 函式引數解構賦值
function f1(obj){
console.log(obj.age);
console.log(obj.height)
}
//等價於
function f1({ age,height }){
console.log(age);
console.log(height)
}
f1({age:5,height:180})
// 陣列解構
function f2([ a,b ]){
console.log(a);
console.log(b)
}
f2([1,2])
- 預設值
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
let [x, y = 'b'] = ['a', null]; // x='a', y=null
// 注意,ES6 內部使用嚴格相等運算子(===),判斷一個位置是否有值。所以,只有當一個數組成員嚴格等於undefined,預設值才會生效,null和0均不生效
模板字串
// 用法:使用``包裹字串,變數使用${}
let s1=3,s2=4;
let s4 = ` a ${s1===1?'1':'2'} b ${s2}`;
console.log(s4);
// 以前的jquery拼接寫法
$('#result').append(
'There are <b>' + basket.count + '</b> ' +
'items in your basket, ' +
'<em>' + basket.onSale +
'</em> are on sale!'
);
// 現在jquery拼接寫法(所有模板字串的空格和換行,都是被保留的)
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
替換
// 只能替換第一個
'aabbcc'.replace('b', '_')
// 使用正則進行替換所有
'aabbcc'.replace(/b/g, '_')
// 現在可以使用replaceAll來替換所有
'aabbcc'.replaceAll('b', '_')
- 箭頭函式
ES6 允許使用“箭頭”(=>)定義函式。
使用注意點
箭頭函式有幾個使用注意點。
(1)函式體內的this物件,就是定義時所在的物件,而不是使用時所在的物件。
(2)不可以當作建構函式,也就是說,不可以使用new命令,否則會丟擲一個錯誤。
(3)不可以使用arguments物件,該物件在函式體內不存在。如果要用,可以用 rest 引數代替。
(4)不可以使用yield命令,因此箭頭函式不能用作 Generator 函式。
//匿名函式
// div.onclick = function () {
// console.log("你好")
// }
// //箭頭函式
// div.onclick = () => {
// console.log("你好")
// }
var f = () => 5;
// 等同於
var f = function () { return 5 };
f();
// 報錯
// let getTempItem = id => { id: id, name: "Temp" };
// 不報錯,直接物件、陣列返回需要用()包裹
let getTempItem = id => ({ id: id, name: "Temp" });
console.log(getTempItem(123));
// 正常函式寫法
let arr = [{ id: 1 }, { id: 2 }, { id: 3 },];
// arr.map(function (x) {
// x.id = x.id * x.id;
// });
// 箭頭函式寫法
arr.map(x => { x.id = x.id * x.id });
console.log(arr);
擴充套件運算子
擴充套件運算子(spread)是三個點(...)。它好比 rest 引數的逆運算,將一個數組轉為用逗號分隔的引數序列。
// 1.修改物件資料
let obj = { pageIndex: 1, pageSize: 10 }
let values = { pageSize: 20 };
// 以前的寫法
obj.pageSize = values.pageSize;
// let payLoad = obj;
// 現在的寫法
let payLoad = { ...obj, ...values };
console.log(payLoad);
// 2.合併陣列
// ES5的 寫法
// var arr1 = [0, 1, 2];
// var arr2 = [3, 4, 5];
// Array.prototype.push.apply(arr1, arr2);
// console.log(arr1);
// ES6 的寫法
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
// arr1.push(...arr2);
arr1 = [...arr1, ...arr2];
console.log(arr1);
// 3.與解構結合,並且擴充套件運算子只能放在最後
const [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first) // 1
console.log(rest) // [2, 3, 4, 5]
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x) // 1
console.log(y) // 2
console.log(z) // { a: 3, b: 4 }
// 4. 克隆合併物件
let a = { name: '123', age: 456 };
let aClone = { ...a };
console.log(aClone);
// 等同於
// let aClone = Object.assign({}, a);
// console.log(aClone);
let b = { name: '1233', age: 4567 };
// let ab = { ...a, ...b };
// 等同於
let ab = Object.assign({}, a, b);
console.log(ab);
陣列的擴充套件
// 1,find:用於找出第一個符合條件的陣列成員。它的引數是一個回撥函式,所有陣列成員依次執行該回調函式,直到找出第一個返回值為true的成員,然後返回該成員。如果沒有符合條件的成員,則返回undefined。
let arr = [1, 4, -5, 10].find((n) => n < 0)
console.log(arr);
// 2.findIndex:用法與find方法非常類似,返回第一個符合條件的陣列成員的位置,如果所有成員都不符合條件,則返回-1
let arr = [1, 5, 10, 15].findIndex(function (value, index, arr) {
return value > 9;
})
console.log(arr);
// 3.includes:判斷元素是否存在 返回true/false
let arr = [1, 5, 10, 15].includes(5);
console.log(arr);// true
// 4.filter:陣列過濾
var arr = [20, 30, 50, 96, 50]
var newArr = arr.filter(item => item > 40)
console.log(newArr)
// 5.every:判斷陣列中是否每個age都大於22
let arr = [
{
name: 'Tom',
age: 22
},
{
name: 'Sun',
age: 23
},
{
name: 'Mack',
age: 25,
sex: '男'
},
]
let newArr = arr.every(item => item.age > 22)
console.log(newArr)
// 6.some:判斷陣列中是否某個age都大於22
arr.some(item => item.age>22)
// 7.reduce:處理陣列,適用於求和、求乘積
var arr = [1, 2, 3, 4];
var sum = arr.reduce((x,y)=>x+y)
var mul = arr.reduce((x,y)=>x*y)
console.log( sum ); //求和,10
console.log( mul ); //求乘積,24
// 8.map:方法返回一個新陣列,陣列中的元素為原始陣列元素呼叫函式處理後的值。
let data = [1, 2, 3, 4, 5]
let nowData = data.map(item => (item = 2));
console.log(nowData, data);
物件的擴充套件
// 1.物件賦值
const foo = 'bar';
const baz = {foo}; // {foo: "bar"}
// 2.陣列key值使用變數
let lastWord = 'last word';
const a = {
'first word': 'hello',
[lastWord]: 'world'
};
a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"
運算元組API
/* 運算元組的常用方法: */
var arr = [10, 20];
/* [1] 在陣列的後面新增元素 arr.push(ele1,ele2...) */
arr.push(30);
arr.push(40, 50, 60);
console.log(arr);
var arr = [10, 20];
/* [2] 在陣列的前面新增元素 arr.unshift(ele1,ele2...)*/
arr.unshift(3);
arr.unshift(88, 888);
console.log(arr);
var arr = [10, 20];
/* [3] 刪除陣列中最後一個元素 */
arr.pop();
console.log(arr);Ï
var arr = [10, 20];
/* [4] 刪除陣列中第一個元素 */
arr.shift();
console.log(arr);
/* [5] 合併陣列的方法 */
/* 語法:arr.concat(ele1|arr,ele2...) */
var arr1 = ["熊大", "熊二"];
var arr2 = ["佩琪", "喬治"];
var arr3 = arr1.concat(arr2);
console.log(arr3);
/* [6] 擷取陣列的方法(不會改變原來的資料) */
/* 語法:arr.slice(startIndex,endIndex) */
/* 注意: */
/* (1) 該方法可以只傳遞一個引數,表示從這個位置開始擷取直到陣列的末尾 */
/* (2) 如果沒有傳遞任何引數,那麼表示擷取整個陣列 */
var data = ["熊大", "熊二", "佩琪", "喬治", 100, 200, "毛毛", "吉吉"];
var res1 = data.slice(1, 4);
console.log(res1);// ["熊二", "佩琪", "喬治"]
var res2 = data.slice(1);
console.log(res2);// ["熊二", "佩琪", "喬治", 100, 200, "毛毛", "吉吉"]
var res3 = data.slice();
console.log(res3);// ["熊大", "熊二", "佩琪", "喬治", 100, 200, "毛毛", "吉吉"]
/* [7] 刪除並插入陣列的方法(會改變原來的資料) */
/* 語法:arr.splice(start,deleteCount.val1,val2,...):從start開始刪除deleteCount項 */
/* 注意: */
/* (1) 該方法可以只傳遞一個引數,表示從這個位置開始擷取直到陣列的末尾 */
/* (2) 如果沒有傳遞任何引數,那麼表示擷取整個陣列 */
var data = ["熊大", "熊二", "佩琪", "喬治", 100, 200, "毛毛", "吉吉"];
data.splice(1, 1, '張三'); // ["熊二", "佩琪", "喬治"]
console.log(data);Ï
/* [8] 將陣列反序 */
/* 語法:arr.reverse(): */
var a = [1, 2, 3, 4, 5]
var b = a.reverse();
console.log(a, b);//a:[5,4,3,2,1] b:[5,4,3,2,1]
/* [9] 新增分割符並變成字串 */
/* 語法:arr.join('|'): */
var a = [1, 2, 3, 4, 5]
var b = a.join("|");
console.log(a, b);//a:[1,2,3,4,5] b:"1|2|3|4|5"
/* [10] 字串按照字元切割成陣列 */
// 2.陣列key值使用變數
let lastWord = 'last,word,hello';
let arr = lastWord.split(',');
console.log(arr);
/* [11] 陣列元素索引並返回元素索引,不存在返回-1,索引從0開始 */
/* 語法:arr.indexOf('a'): */
var a = ['a', 'b', 'c', 'd', 'e'];
console.log(a.indexOf('a'));//0
console.log(a.indexOf('h'));//-1
/* [12] 陣列元素排序 */
/* 語法:arr.sort(): */
var arr = [{ age: 1 }, { age: 5 }, { age: 3 }, { age: 2 },];
arr.sort((num1, num2) => num1.age - num2.age);
console.log(arr);Ï
Promise
Promise 是非同步程式設計的一種解決方案,比傳統的解決方案——回撥函式和事件——更合理和更強大
Promise物件代表一個非同步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)
// 輸出:1 2 3(Promise 新建後立即執行,所以首先輸出的是1。然後,then方法指定的回撥函式,將在當前指令碼所有同步任務執行完才會執行,所以輸出2,resolved3最後輸出。)
const promise = new Promise(function (resolve, reject) {
console.log(1);
if (true) {
setTimeout(() => {
resolve(3);
}, 1000);
} else {
reject(error);
}
});
console.log(2);
promise.then(function (value) {
console.log(value);
return value;
}, function (error) {
});
// Promise.all:3秒後輸出promise1 promise2
const promise1 = new Promise(function (resolve, reject) {
setTimeout(() => {
resolve('promise1');
}, 1000);
});;
const promise2 = new Promise(function (resolve, reject) {
setTimeout(() => {
resolve('promise2');
}, 3000);
});
// 所有非同步方法成功之後才會執行,如果有一個返回rejected則會返回rejected
Promise.all([
promise1,
promise2
]).then(([res1, res2]) => {
console.log(res1, res2);
});
Async
async函式返回一個 Promise 物件,可以使用then方法添加回調函式。當函式執行的時候,一旦遇到await就會先返回,等到非同步操作完成,再接著執行函式體內後面的語句。
// 正常情況下,await命令後面是一個 Promise 物件,返回該物件的結果。如果不是 Promise 物件,就直接返回對應的值。
async function f() {
return 'hello world';
}
f().then(v => console.log(v))
// "hello world"
function timeout(value) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(value);
}, 3000);
});
}
async function asyncPrint(value) {
console.log(1111);
let nowValue = await timeout(value);
console.log(nowValue);
console.log(222);
}
asyncPrint('3333',);
import export
ES6模組功能主要有兩個命令構成:export和import。export命令用於規定模組的對外介面,import命令用於輸入其他模組提供的功能。
- export
// 1. 直接輸出變數(方法、類)
export var m = 1;
export function multiply(x, y) {
return x * y;
};
// 2. 使用大括號指定所要輸出的一組變數(方法、類)
var m = 1;
export { m };
// 3. as關鍵字重新命名
// 重新命名後,v2可以用不同的名字輸出兩次
function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
- import
使用export命令定義了模組的對外介面以後,其他 JS 檔案就可以通過import命令載入這個模組。import命令接受一對大括號,裡面指定要從其他模組匯入的變數名。大括號裡面的變數名,必須與被匯入模組對外介面的名稱相同。
// 1. 引入變數(方法、類)-(逐一載入),引入的名字要和匯出的名字相同
import { firstName, lastName, year } from './profile.js';
// 2. as關鍵字重新命名
import { lastName as surname } from './profile.js';
// 3. 整體載入
import * as circle from './circle';
- export default
export default就是輸出一個叫做default的變數或方法,系統允許自定義命名
// 預設輸出一個函式
function getName() {
console.log('foo');
}
export default getName;
// 引用並指定名字(可以按別的名字命名)
import customName from './export-default';
- 實用的程式碼
// 1.判斷值是否存在(a為null、undefined、0都隱性轉換為false),常用在判斷值存不存在,陣列長度是不是0
if(a){
}
// 2.獲取變數給預設值(0 null undefined false '')
var a= '';
let b = a||'預設值';