1. 程式人生 > 實用技巧 >第八課之提高開發效率的es6以及函式

第八課之提高開發效率的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||'預設值';