重學ES6基礎語法(二)

acoderbeauty發表於2019-10-12

本系列部落格為ES6基礎語法的使用及總結,如有錯誤,歡迎指正。 重學ES6基礎語法(二)主要包括 預設引數值模板字串解構賦值剩餘引數擴充套件運算子 等。

預設引數值(Default parameters)

函式預設引數允許在沒有值或undefined被傳入時使用預設形參。

1.語法

function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) { 
    statements 
}
複製程式碼

2.使用

2.1 在ES6之前可以通過邏輯運算子來給形參指定預設值

格式: 條件A || 條件B

如果條件A成立, 那麼就返回條件A;

如果條件A不成立, 無論條件B是否成立, 都會返回條件B。

 function getInfo(a, b) {
    a = a || "今天要少吃,";
    b = b || "明天也要少吃";
    console.log(a, b);
}
getInfo(); //列印預設值 --> 今天要少吃,明天也要少吃
getInfo("mss"); //相當於傳遞了引數a,未傳引數b --> mss 明天也要少吃
getInfo(undefined,"mss"); //表示引數a是未知的,此時採用預設值 --> 今天要少吃, mss
getInfo(123, "abc"); //引數ab都是由外界傳遞的 --> 123 "abc"
複製程式碼

2.2 從ES6開始直接通過變數=指定預設值即可給形參指定預設值

function getInfo(a = "今天要少吃", b = ", 明天也要少吃") {
    console.log(a, b);
};
getInfo(); //今天要少吃, 明天也要少吃
getInfo(123, "abc"); //123 "abc"
複製程式碼

注意:① 如果只傳遞了一個引數,則代表第一個引數使用我們傳遞進來的,其他引數還是使用預設值。

② 如果需要給某一個引數指定內容,其他引數需要傳遞undefined

③ 問:給其他引數傳遞null可以嗎?答:別問,問就是不可以,問就是讓你自己回去試

function multiply(a = 3, b = 5) {
   return a * b;
}
console.log(multiply(5, 2)); // ab均為傳遞進來的值,為10
console.log(multiply(5)); // a是5,b是預設值5,結果為25
console.log(multiply(undefined,10)); //a是預設值3,b是10,結果為30

function test(a = 1,b = 2, c = 3, d = 4) {
    return a + b + c + d;
}
console.log(test(undefined, undefined, 4, undefined)); //11
複製程式碼

2.3 ES6中的預設值還可以從其它的函式中獲取

function getSum(a = "少吃,", b = getDefault()) {
    console.log(a, b);
}
getSum();
// getSum(123, "abc");
function getDefault() {
    return "零食";
}
複製程式碼

模板字串(Template literals (Template strings))

模板字面量 是允許嵌入表示式的字串字面量。你可以使用多行字串和字串插值功能。

1.語法

將需要插入的內容放在一對反引號``裡面

模板字串使用反引號來代替普通字串中的用雙引號和單引號。模板字串可以包含特定語法(${expression})的佔位符。佔位符中的表示式和周圍的文字會一起傳遞給一個預設函式,該函式負責將所有的部分連線起來,如果一個模板字串由表示式開頭,則該字串被稱為帶標籤的模板字串,該表示式通常是一個函式,它會在模板字串處理後被呼叫,在輸出最終結果前,你都可以通過該函式來對模板字串進行操作處理。在模版字串內使用反引號(`)時,需要在它前面加轉義符(\)。

`string text` //單行

`string text line 1
 string text line 2` //多行

`string text ${expression} string text` //包含特定語法(${expression})的佔位符

tag `string text ${expression} string text` //標籤模板字串
複製程式碼

2.用法

2.1 在ES6之前可以通過加號實現字串拼接,但有時建立標籤時不能體現出html標籤的層級結構,比較繁瑣而且容易出錯。

let name = 'ghk';
let age = 22;
let output = name + ' is ' + age;
console.log(output);
複製程式碼

2.2 採用模板字串簡化操作,引入的變數用${}包裹起來,${expression}中的expression的內容可以是一個變數、物件的屬性、也可以是一個函式、一個需要建立的標籤

let name = 'ghk';
let age = 22;
let output2 = `${name} is ${age}`;
console.log(output2);

let output3 = `${name} is ${age * 3}`;
console.log(output3);
複製程式碼

2.3 模板字串書寫上可以自由換行,而不用新增“\”反斜槓轉義空格

模板字串建立標籤時,有時會保留標籤前後的空格,不需要空格時可以用.trim()方法去除空格(模板字串也是個字串)。

let str = `<div>
    <p><img src="./images.test.jpg" alt=""></p>
</div>`

let str = `
<div>
    <p><img src="./images.test.jpg" alt=""></p>
</div>`.trim();
console.log(str);
複製程式碼

2.4 模板字串裡面可巢狀模板字串

let person = {
    name: 'mss',
    lists:[
        {task: 'reading'},
        {task: 'sleeping'},
        {task: 'eating'}
    ]
};
let template = `
    <ul>
         ${person.lists.map(list =>`
             <li>
                 ${list.task}
             </li>
         `).join('')}
    </ul>
`;
document.body.innerHTML = template;
複製程式碼

標籤模板字串(Tagged templates)

標籤模板字串允許通過一個預設的函式對其中的插值進行運算和連線。

更高階的形式的模板字串是帶標籤的模板字串。標籤使您可以用函式解析模板字串。標籤函式的第一個引數包含一個字串值的陣列。其餘的引數與表示式相關。最後,你的函式可以返回處理好的的字串(或者它可以返回完全不同的東西)。用於該標籤的函式的名稱可以被命名為任何名字。

1.用法

1.1 標籤函式第一個引數(strings)是一個陣列,是由字串的字面量組成的一個陣列;後面的引數是不定引數(即變數),一個引數代表一個表示式的計算結果。

function myTag(strings, ...values) {
   console.log(strings);
   console.log(values);
}
let name = 'ghk';
let task = 'learning English';
let output = myTag`${name} has planned to ${task}`;
複製程式碼

重學ES6基礎語法(二)
1.2 當然了,不定引數是可以分開寫的,但是如果有多個引數的時候建議還是使用 ...values 來代替

function myTag(strings,name,task) {
   console.log(strings);
   console.log(name);
   console.log(task);
}
let name = 'ghk';
let task = 'learning English';
let output = myTag`${name} has planned to ${task}`;
複製程式碼

重學ES6基礎語法(二)
2.注意點

2.1 當模板字串是以變數開頭或者結尾的時候,返回的陣列前或者後會多一個空字串

重學ES6基礎語法(二)
如果此時在模板字串前後加上一些內容,前後就不會返回空字串了

function myTag(strings,...values) {
   console.log(strings);
   console.log(values);
}
let name = 'ghk';
let task = 'learning English';
let output = myTag`the boy ${name} has planned to ${task}.`;
複製程式碼

重學ES6基礎語法(二)
2.2 在上述中使用了標籤函式建立的模版字串,但沒有在標籤函式中return最終值,所以output是undefined。要想有最終結果需要在標籤函式中將字串字面量陣列和表示式運算結果拼接起來返回。

function myTag(strings,...values) {
   //console.log(strings);
   //console.log(values);
   let arr = [];
   for (let i=0;i<strings.length;i++){
       arr.push(strings[i]);
       arr.push(values[i]);
   }
   return arr.join("");
}
let name = 'ghk';
let task = 'learning English';
let output = myTag`the boy ${name} has planned to ${task}.`;
console.log(output); //the boy ghk has planned to learning English.
複製程式碼

3.原始字串

3.1 在標籤函式的第一個引數中,存在一個特殊的屬性raw ,我們可以通過它來訪問模板字串的原始字串,而不經過特殊字元的替換。

3.2 使用String.raw() 方法建立原始字串和使用預設模板函式和字串連線建立是一樣的。

let name = 'ghk';
let task = 'learning English';
let str=String.raw`the boy ${name} has planned to ${task}.`;
console.log(str); //the boy ghk has planned to learning English.
複製程式碼

解構賦值(Destructuring assignment)

解構賦值語法是一種 Javascript 表示式。通過解構賦值, 可以將屬性/值從物件/陣列中取出, 賦值給其他變數。

一句話:解構賦值是ES6中新增的一種賦值方式

解構陣列(Array destructuring)

1.用法

1.1 解構陣列就是在表示式左邊定義了要從原變數中取出什麼變數。如果想要取出非連續變數的值,需要用加上逗號,表示留出跳過的元素的位置。

let arr= [1,2,3,4,5];
let [a,b] = arr;
// 相當於以下兩句
// let a = arr[0];
// let b = arr[1];
console.log(a); //1
console.log(b); //2

let [one,,three,four] = arr;
console.log(one); //1
console.log(three); //3
console.log(four); //4
複製程式碼

1.2 在陣列的解構賦值中, 還可以使用ES6中新增的剩餘引數來打包剩餘的資料;如果使用了剩餘引數, 則只能寫在最後一個變數的前面。

let [a, ...b] = [1, 3, 5];
console.log("a = " + a); //1
console.log("b = " + b);  //[3,5]

//SyntaxError: Rest element must be last element
let [a, ...b,c] = [1, 3, 5];
console.log("a = " + a);
console.log("b = " + b);
console.log("c = " + c);
複製程式碼

2.注意點

2.1 在陣列的解構賦值中, 等號左邊的格式必須和等號右邊的格式一模一樣, 才能完全解構。

let [a, b, [c, d]] = [1, 3, [2, 4]]; //完全解構
console.log("a = " + a); //1
console.log("b = " + b); //2
console.log("c = " + c); //3
console.log("d = " + d); //4

let [a, b, c] = [1, 3, [2, 4]]; //未完全解構
console.log("a = " + a); //1
console.log("b = " + b); //3
console.log("c = " + c); //2,4
複製程式碼

2.2 在陣列的解構賦值中, 等號左邊的變數個數可以和右邊的個數不一樣,右邊的個數也可以和左邊的個數不一樣; 如果右邊的個數和左邊的個數不一樣, 可以給左邊指定預設值。

let [a, b] = [1, 3, 5];
console.log("a = " + a); //1
console.log("b = " + b); //3

let [a, b, c] = [1];
console.log("a = " + a); //1
console.log("b = " + b); //undefined
console.log("c = " + c); //undefined

let [a, b = 666] = [1, 3, 5];
console.log("a = " + a); //1
console.log("b = " + b); //3
複製程式碼

3.應用場景

可以用作變數交換,在一個解構表示式中可以交換兩個變數的值。 沒有解構賦值的情況下,交換兩個變數需要一個臨時變數

let a = 1;
let b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
複製程式碼

解構物件(Object destructuring)

陣列解構使用[],物件解構使用{},其他用法差別不大。

1.用法(基本賦值)

let obj = {
   name: 'ghk',
   age: 22,
   gender: 'male'
};

let {name, age,gender} = obj;
// 相當於下面幾句程式碼
// let name = obj.name;
// let age = obj.age;
// let gender = obj.gender;
// let {name, age, gender} = {name: 'ghk',age: 22,gender: 'male'};
console.log(name, age, gender);
複製程式碼

2.無宣告賦值

一個變數可以獨立於其宣告進行解構賦值。

在使用物件字面量無宣告解構賦值時,必須在賦值語句周圍加上圓括號 ( ) 。

( ) 表示式之前需要有一個分號,否則它可能會被當成上一行中的函式執行。

//正確用法
let a, b;
({a, b} = {a: 1, b: 2});

//錯誤寫法,執行也會報錯
let a, b;
{a, b} = {a: 1, b: 2};
console.log(a);
console.log(b);
複製程式碼

注:{a, b} = {a: 1, b: 2} 不是有效的獨立語法,因為左邊的 {a, b}被認為是一個塊而不是物件字面量。 ({a, b} = {a: 1, b: 2}) 是有效的,相當於var {a, b} = {a: 1, b: 2}

3.注意點

3.1 物件解構只會解構出等號左邊出現過的屬性名,且左邊的變數名稱必須和物件的屬性名稱一致, 才能解構出資料。

let {name} = {name: "ghk",age: 22};
console.log(name); //ghk
let {age} = {name: "ghk",age: 22};
console.log(age); // 34

let {a, b} = {name: 'ghk', age: 22,};
console.log(a, b); // undefined undefined
複製程式碼

3.2 左邊屬性名可以多於右邊,也可以給左邊指定預設值

let {name, age, gender} = {name: "ghk",age: 22};
console.log(name, age, gender); // gender是undefined

let {name, age, gender = 'male'} = {name: "ghk",age: 22};
console.log(name, age, gender);
複製程式碼

4.物件解構是可以巢狀的

const data = {
    name: 'ghk',
    age: 22,
    skill: {
        language: 'japanese',
        instrument: 'piano',
        hobby: 'hiking',
    }
};
let {language,instrument,hobby} = data.skill;
console.log(language, instrument, hobby);
複製程式碼

剩餘引數(rest parameter)

1.用法

剩餘引數 語法允許我們將一個不定數量的參數列示為一個陣列。

一句話:剩餘引數是把很多引數整合成一個陣列

function sum(...numbers) {
    //number是一個真陣列,儲存了傳進來的所有的變數
    console.log(numbers); 
    //既然返回的是一個陣列,那麼就可以使用陣列的各種方法了
    return numbers.reduce((prev,curr) => prev + curr,0)
}
console.log(sum(1, 2, 3, 4)); //10
複製程式碼

2.使用 剩餘引數 和使用 arguments 儲存引數的區別?

  • 剩餘引數儲存引數返回的是一個真陣列
  • 利用arguments儲存引數返回一個類陣列物件
function sum2() {
    console.log(arguments); //arguments返回一個類陣列物件
}
sum2(1,2,3,4);
複製程式碼

重學ES6基礎語法(二)
3.剩餘引數應用場景

3.1 對函式引數的處理(箭頭函式中使用),後續可以直接用陣列的API處理

3.2 變數的解構,把剩餘引數打包到一個陣列中

//箭頭函式中使用
let sum = (...args) => {
    return args.reduce((prevSum,curValue) => prevSum + curValue);
};
console.log(sum(1, 2, 3));

//把分數解構到score陣列中
const player = ['ghk',22,5.4,5.6,7.8,9.9,4.4,6.8];
const [name, age, ...score] = player;
console.log(name);
console.log(age);
console.log(score);
複製程式碼

擴充套件運算子(spread operator)

把一個可遍歷物件轉為一個用逗號分隔的新的引數序列,相當於剩餘引數的逆運算

什麼是可遍歷物件?

就是部署了iterator介面,可以用for of迴圈的資料型別。包括字串、陣列、arguments物件,DOM、NodeList物件,Generator物件等

1.用法

const arr1 = ['1','1','1','1'];
const arr2 = ['2','2','2'];
//連線陣列的作用
let list = [...arr1,...arr2];
console.log(list);// ["1", "1", "1", "1", "2", "2", "2"]


//連線陣列並在相應位置插入元素
let list2 = [...arr1,'separate',...arr2];
console.log(list2); // ["1", "1", "1", "1", "separate", "2", "2", "2"]
let list3 = [...arr1,...arr2,'end'];
console.log(list3);// ["1", "1", "1", "1", "2", "2", "2", "end"]
let list4 = ['start',...arr1,...arr2];
console.log(list4);// ["start", "1", "1", "1", "1", "2", "2", "2"]
複製程式碼

2.rest parameter和spread operator的區別

Just as the spread operator allows you to expand an array into its individual elements, the rest parameter lets you bundle elements back into an array.

推薦看這篇,嘻嘻(齜牙笑) An intro to the spread operator and rest parameter in JavaScript (ES6)

3.擴充套件運算子可以用來連線陣列、克隆陣列

下例中newArr複製了arr的元素,修改newArr第一個元素,並不會影響到arr (相當於深拷貝)

let arr1 = ['mary','mark','bob','lily'];
let arr2 = ['tom','eli','jade'];
let arr = [...arr1,...arr2];
console.log(arr); //["mary", "mark", "bob", "lily", "tom", "eli", "jade"]
let newArr = [...arr]; 
console.log(newArr); //["mary", "mark", "bob", "lily", "tom", "eli", "jade"]
newArr[0] = 'rachel';
console.log(newArr); //["rachel", "mark", "bob", "lily", "tom", "eli", "jade"]
console.log(arr); //["mary", "mark", "bob", "lily", "tom", "eli", "jade"]
複製程式碼

4.擴充套件運算子可以在函式中使用

let fruits = ['banana','apple','orange'];
let newFruits = ['peach','pear'];
fruits.push(...newFruits);
console.log(fruits);

let time = [2019,10,23];
let date = new Date(...time);
console.log(date);
複製程式碼

ES6物件字面量增強寫法(Object Literal Upgrades)

1.過去定義一個物件的寫法

const obj = {
  name: 'ghk',
  age: 18,
  gender: 'male',
  greet: function () 
    console.log(hello);
  }
}
複製程式碼

2.當一個物件的屬性是從外面獲取的時候,可以採用下面這種方式

const name = 'ghk';
const age = 18;
const gender = 'man';
  
const obj = {
  name,
  age,
  gender,
  getName(){
    console.log(this.name);
  }
};
複製程式碼

3.相關閱讀

github.com/wesbos/es6-…


本文章參考到的連結:

developer.mozilla.org/en-US/docs/…

webfront-js.com/articaldeta…

www.freecodecamp.org/news/spread…