本文轉(zhuǎn)載自我的個人博客。
ES6新標(biāo)準(zhǔn)的知識點(diǎn)零散,經(jīng)常是看一遍就忘了,所以特別開了這一貼,作為一個ES6知識的匯總貼。主要講ES6的新命令的具體用法,以及與之前用法的區(qū)別。知識點(diǎn)不會講得很深,很多只是蜻蜓點(diǎn)水的講一下,適合當(dāng)作ES6的入門貼來看。本帖長期更新,實(shí)用向。
let 命令
ES6 新增了一個 let命令用來聲明變量。同樣是聲明變量,let與之前的var主要有以下幾點(diǎn)區(qū)別:
-
let聲明的變量不允許重復(fù)聲明:
var a = 1;
var a = 2;
console.log(a); //輸出 2
let b = 1;
let b = 2; //報(bào)錯
console.log(b) ;
在一個大型項(xiàng)目中或者多人協(xié)助項(xiàng)目中,我們往往因?yàn)椴恢滥切┳兞恳呀?jīng)被聲明過了而重復(fù)聲明變量,導(dǎo)致之前變量的值被覆蓋。由于程序不會報(bào)錯,debug是很困難的,而現(xiàn)在的let命令很好的解決了這個問題。
-
let聲明的變量存在塊級作用域:
function f1() {
let n = 5;
if (true) {
let n = 10;
console.log(n); //輸出 10
}
console.log(n); // 輸出 5
}
上面的兩個代碼塊中擁有各自的變量n,不會相互影響。
再給一個例子:
///////// 使用 var /////////
var printNumTwo;
for (var i = 0; i < 3; i++) {
if(i === 2){
printNumTwo = function() {
return i;
};
}
}
console.log(printNumTwo());
// returns 3
///////// 使用 let /////////
'use strict';
let printNumTwo;
for (let i = 0; i < 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i;
};
}
}
console.log(printNumTwo());
// returns 2
console.log(i);
// returns "i is not defined"
-
let聲明不存在變量提升
所謂變量提升,就是之前我們在使用var聲明變量時,變量可以放在聲明之前使用,只不過使用還沒有聲明的變量時,其值為undefined。但是使用let聲明變量時,如果使用放在聲明之前則會報(bào)錯。
console.log(a); //輸出 undefined
var a = 1;
console.log(b); //報(bào)錯
let b = 1;
const 命令
const除了擁有let的所有優(yōu)秀特性(不允許重復(fù)聲明,有用塊級作用域)之外,還有一個特性,那就是它是只讀的。
“ const 實(shí)際上保證的,并不是變量的值不得改動,而是變量指向的那個內(nèi)存地址不得改動。對于簡單類型的數(shù)據(jù)(數(shù)值、字符串、布爾值),值就保存在變量指向的那個內(nèi)存地址,因此等同于常量。但對于復(fù)合類型的數(shù)據(jù)(主要是對象和數(shù)組),變量指向的內(nèi)存地址,保存的只是一個指針, const 只能保證這個指針是固定的,至于它指向的數(shù)據(jù)結(jié)構(gòu)是不是可變的,就完全不能控制了。”
《ES6標(biāo)準(zhǔn)入門》 阮一峰
阮大佬上面這段話具體是什么意思呢,請看下面這個例子:
"use strict";
const s = [5, 6, 7];
s = [1, 2, 3]; // 報(bào)錯
s[2] = 45; // 正常工作
console.log(s); // returns [5, 6, 45]
我們將一個新數(shù)組[1, 2, 3]賦值給變量s時,其實(shí)是企圖改變變量s內(nèi)指針的指向,而因?yàn)樽兞?code>s是使用const命令聲明的,其指針指向是固定的,不能變動的,所以程序報(bào)錯。第二次,我們想修改數(shù)組中第二項(xiàng)的值,因?yàn)樾薷臄?shù)組中某一項(xiàng)的值并不改變數(shù)組的地址,變量s內(nèi)所保存的指針依舊指向原來的地址,所以程序可以成功執(zhí)行。
Object.freeze
因?yàn)?code>const并不能保證復(fù)合類型的數(shù)據(jù)是不可改變的,所以我們需要一個新的命令來保證復(fù)合類型的只讀性,這個命令就是Object.freeze,具體用法請看下例:
let person = {
name:"XiaoMing",
review:"yes"
};
Object.freeze(person);
person.review = "no"; //這條命令將會被忽略,因?yàn)榇藭rperson對象是只讀的
person.newProp = "age"; // 這條命令也將會被忽略
console.log(obj);
// { name: "XiaoMing", review:"yes"}
箭頭函數(shù) (Arrow Functions)
ES6 為我們帶來了一種更簡潔的書寫函數(shù)的方式,箭頭函數(shù)。在舊的標(biāo)準(zhǔn)中,我們是這樣書寫函數(shù)的:
const myFunc = function() {
const myVar = "value";
return myVar;
}
使用剪頭函數(shù),我們可以將其簡化為:
const myFunc = () => {
const myVar = "value";
return myVar;
}
還可以進(jìn)一步簡化,我們可以甚至連return都不要:
const myFunc = () => "value"
箭頭函數(shù)可以傳參:
// 將輸入的數(shù)乘以2,并返回
const doubler = (item) => item * 2;
箭頭函數(shù)可以極大的化簡高階函數(shù)的使用。所謂高階函數(shù),就是那些接受一個函數(shù)作為參數(shù)的函數(shù),常見的有:map(),filter(),reduce()。在以前我們是這么寫高階函數(shù)的:
FBPosts.filter(function(post) {
return post.thumbnail !== null && post.shares > 100 && post.likes > 500;
})
利用箭頭函數(shù)可以化簡為一行:
FBPosts.filter((post) => post.thumbnail !== null && post.shares > 100 && post.likes > 500)
為函數(shù)的參數(shù)設(shè)置默認(rèn)值
在ES6中,你可以為函數(shù)的參數(shù)設(shè)置默認(rèn)值:
function greeting(name = "Anonymous") {
return "Hello " + name;
}
console.log(greeting("John")); // 輸出 Hello John
console.log(greeting()); // 輸出 Hello Anonymous
參數(shù)name的默認(rèn)值被設(shè)置為"Anonymous",所以在不傳參直接調(diào)用greeting()時,輸出的是Hello Anonymous。
rest 參數(shù) (Rest Operator)
ES6中引入了rest參數(shù),其形式為...變量名。通過使用rest參數(shù),你可以向函數(shù)傳入不同數(shù)量的參數(shù):
function howMany(...args) {
return "You have passed " + args.length + " arguments.";
}
console.log(howMany(0, 1, 2)); // 傳入三個參數(shù)
console.log(howMany("string", null, [1, 2, 3], { })); // 傳入四個參數(shù)
rest參數(shù)中的變量代表一個數(shù)組,所有數(shù)組特有的方法都可以用于這個變量:
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
console.log(a) //輸出 [1, 2, 3]
rest參數(shù)之后不能再有其他參數(shù),否則程序會報(bào)錯。
擴(kuò)展運(yùn)算符 (Spread Operator)
擴(kuò)展運(yùn)算符其實(shí)就是rest參數(shù)中的那三個點(diǎn)...,其作用是將數(shù)組打散:
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
在之前,如果我們想求數(shù)組中的最大值需要這樣寫:
var arr = [6, 89, 3, 45];
var maximus = Math.max.apply(null, arr); // 返回 89
因?yàn)?code>Math.max()方法只接受由逗號分隔的參數(shù)序列,比如Math.max(1, 2, 3),所以我們需要apply()進(jìn)行轉(zhuǎn)化。在ES6中,我們不再需要apply()方法,而是可以直接利用擴(kuò)展運(yùn)算符,其形式更易于理解:
const arr = [6, 89, 3, 45];
const maximus = Math.max(...arr); // 返回 89
請注意,擴(kuò)展運(yùn)算符...只在某些特定的情況下才可以使用,比如函數(shù)的參數(shù)中,或者數(shù)組中。裸用擴(kuò)展運(yùn)算符程序會報(bào)錯:
var arr = [6, 89, 3, 45]
const spreaded = ...arr; //報(bào)錯
解構(gòu)賦值(Destructuring Assignment)
我們已經(jīng)看過了擴(kuò)展運(yùn)算符可以讓我們的數(shù)組操作變得多么高效。對于操作對象,ES6也給出了相似的方法。
- 請看下面這個
ES5的例子:
var voxel = {x: 3.6, y: 7.4, z: 6.54 };
var x = voxel.x; // x = 3.6
var y = voxel.y; // y = 7.4
var z = voxel.z; // z = 6.54
在ES6中,我們可以這樣做:
const { x, y, z } = voxel; // x = 3.6, y = 7.4, z = 6.54
如果你想賦值的變量與對象的屬性有不同的名稱,你可以這樣做:
const { x : a, y : b, z : c } = voxel // a = 3.6, b = 7.4, c = 6.54
以上操作方法被我們稱為解構(gòu)賦值。
- 解構(gòu)賦值也可以作用于嵌套的對象:
const a = {
start: { x: 5, y: 6},
end: { x: 6, y: -9 }
};
const { start : { x: startX, y: startY }} = a;
console.log(startX, startY); // 5, 6
- 利用解構(gòu)賦值,我們可以輕易的獲取數(shù)組的特定元素:
const [a, b] = [1, 2, 3, 4, 5, 6];
console.log(a, b); // 1, 2
const [a, b,,, c] = [1, 2, 3, 4, 5, 6];
console.log(a, b, c); // 1, 2, 5
- 解構(gòu)賦值可以搭配擴(kuò)展運(yùn)算符使用
const [a, b, ...arr] = [1, 2, 3, 4, 5, 7];
console.log(a, b); // 1, 2
console.log(arr); // [3, 4, 5, 7]
- 如果你想將一個對象當(dāng)參數(shù)傳入,你可能會想到這樣做:
const profileUpdate = (profileData) => {
const { name, age, nationality, location } = profileData;
// 函數(shù)操作
}
但其實(shí)你可以這樣:
const profileUpdate = ({ name, age, nationality, location }) => {
// 函數(shù)操作
}
這樣做的好處是,我們不用把整個對象都傳進(jìn)來,只需要傳入我們需要的那部分。
模板字符串 (Template String)
ES6中引入了一種更強(qiáng)大的字符串寫法,被稱為模板字符串,用反引號( ` )標(biāo)識,用法如下:
const person = {
name: "Zodiac Hasbro",
age: 56
};
//用模板字符串方式書寫的字符串,并將其賦給greeting變量
const greeting = `Hello, my name is ${person.name}!
I am ${person.age} years old.`;
console.log(greeting);
// 輸出:
// Hello, my name is Zodiac Hasbro!
// I am 56 years old.
在上面這段代碼中,有三個地方需要我們注意:
- 模板字符串的標(biāo)識符是反引號
(`)而不是單引號(') - 輸出的字符串是多行的,我們在也不需要
\n了 - 語法
${}可以用來獲取變量,化簡了之前用+來進(jìn)行字符串拼接的寫法
更簡潔的定義對象的方法
在ES5中我們是這樣定義對象的方法的:
const person = {
name: "Taylor",
sayHello: function() {
return `Hello! My name is ${this.name}.`;
}
};
在ES6中,我們可以將function關(guān)鍵詞省略:
const person = {
name: "Taylor",
sayHello() {
return `Hello! My name is ${this.name}.`;
}
};
class
ES6中提供了一種新的語法創(chuàng)建對象,即使用class關(guān)鍵詞。需要注意的是,這里的class關(guān)鍵詞只是語法糖,并不具有像傳統(tǒng)的面向?qū)ο蟮恼Z言那樣的特性。
在ES5中,我們通常是這樣創(chuàng)建構(gòu)造函數(shù)的:
var Person = function(name){
this.name = name;
}
var person1 = new Person('Jim');
利用class語法糖,我們可以這樣寫:
class Person {
constructor(name){
this.name = name;
}
}
const person1 = new Person('Jim');
在由class定義的對象中,我們添加了構(gòu)造函數(shù)constructor(),構(gòu)造函數(shù)在new被調(diào)用時喚醒,創(chuàng)建一個新的對象。
用取值函數(shù)和存值函數(shù)(getters and setters)來封裝對象
在由class定義的對象中,存值函數(shù)和取值函數(shù)現(xiàn)在有了自己的關(guān)鍵字get和set,用法也更加簡單:
class Book {
constructor(author) {
this._author = author;
}
// getter
get writer(){
return this._author;
}
// setter
set writer(updatedAuthor){
this._author = updatedAuthor;
}
}
const lol = new Book('anonymous');
console.log(lol.writer); // anonymous
lol.writer = 'wut';
console.log(lol.writer); // wut
請注意我們調(diào)用存值函數(shù)和取值函數(shù)的方式:lol.writer。這種調(diào)用方式讓他們看起來并不像是函數(shù)。