歡迎訪問我的博客https://qqqww.com/,祝碼農(nóng)同胞們早日走上人生巔峰,迎娶白富美~~~
由于沒寫目錄,移步https://blog.csdn.net/weixin_43307658/article/details/86698281體驗(yàn)更好
1 Babel 轉(zhuǎn)碼
請移步我的另一篇博客ES6-Babel轉(zhuǎn)碼
2 聲明變量
在
ES6中常用let或const來聲明變量,下面介紹let和const
2.1 let
ES6 新增了
let命令,用來聲明變量。它的用法類似于var,但是所聲明的變量,只在let命令所在的代碼塊內(nèi)有效
2.1.1 引入 let 的好處
我們在
ES5中使用var來聲明變量,但是var的變量提升往往會帶來一些問題:
// 使用 var
console.log(a) // 輸出 undefined
var a = 1
// 使用 let
console.log(b) // 輸出 ReferenceError
let b = 1
一般我們認(rèn)為應(yīng)該先聲明變量再使用,但是這里使用
var聲明的變量卻能提前使用,而不報錯,本身在邏輯性上可能會覺得不太好,但是還沒有看到具體會引起什么錯誤,那么再看下面的代碼:
var a = new Date() // Tue Jan 29 2019 20:31:15 GMT+0800 (中國標(biāo)準(zhǔn)時間)
function fn () {
cosole.log(a)
if (false) {
a = 'hello'
console.log(a)
}
}
fn() // undefined
上述代碼由于
if代碼塊使用內(nèi)層的變量,外面的使用外層的變量,看似互不影響,但是由于var存在變量提升,導(dǎo)致內(nèi)層的a覆蓋了外層的a,甚至有可能將局部變量提升為全局變量,以后有可能引起內(nèi)存泄漏
所以引入
let,let聲明的變量有自己獨(dú)立的作用域塊,let聲明的變量只在let所在的塊內(nèi)起作用,不再受外部影響,形成暫時性死區(qū),有效防止變量提升問題暫時性死區(qū):在代碼塊內(nèi),使用
let命令聲明變量之前,該變量都是不可用的
我們將上述代碼中的
var換為let看看
let a = new Date() // Tue Jan 29 2019 20:31:15 GMT+0800 (中國標(biāo)準(zhǔn)時間)
function fn () {
cosole.log(a)
if (false) {
a = 'hello'
console.log(a)
}
}
fn() // Tue Jan 29 2019 20:31:15 GMT+0800 (中國標(biāo)準(zhǔn)時間)
這時候就不存在變量提升的問題了
2.1.2 let 規(guī)則
使用
let聲明的變量可以重新賦值,但是不能在同一作用域內(nèi)重新聲明
2.2 const
const和let引入的好處基本一樣,但是為什么還要引入呢?看看下面的const規(guī)則:使用
const聲明的變量必須賦值初始化,但是不能在同一作用域類重新聲明也無法重新賦值它們的區(qū)別就在于規(guī)則,其他幾乎一模一樣
3 模板字面量
ES6中的模板字面量就是通過一種更加簡便的方法去拼接字符串,在以前我們常通過+或者concat()等方法去拼接字符串
const dog1 = {
name: 'dahuang',
age: 10
}
const dog2 = {
name: 'xiaohei',
age: 10
}
let mes = dog1.name + 'and' + dog2.name + 'are dog'
下面用模板字面量去拼接字符串
let mes = `${dog1.name} and ${dog2.name} are dog`
一對反引號搞定
4 解構(gòu)賦值
ES6 允許按照一定模式,從數(shù)組和對象中提取值,對變量進(jìn)行賦值,這被稱為解構(gòu)(Destructuring)
以前為變量賦值,只能直接指定值,下面來自阮一峰老師的文檔里的一個小例子
let a = 1
let b = 2
let c = 3
ES6允許下面這樣
let [a, b, c] = [1, 2, 3]
上面代碼表示,可以從數(shù)組中提取值,按照對應(yīng)位置,對變量賦值
解構(gòu)賦值的規(guī)則是,只要等號右邊的值不是對象或數(shù)組,就先將其轉(zhuǎn)為對象。由于
undefined和null無法轉(zhuǎn)為對象,所以對它們進(jìn)行解構(gòu)賦值,都會報錯
let { prop: x } = undefined // TypeError
let { prop: y } = null // TypeError
4.1 數(shù)組的解構(gòu)賦值
const arr = [1, 2, 3]
const [a, b, c] = arr
console.log(a, b, c) // 1, 2, 3
4.2 對象的解構(gòu)賦值
let { foo1, foo2 } = { foo1: 'a', foo2: 'b' }
// foo1 => 'a' foo2 => 'b'
對象字面量的寫法:
let name = 'dahuang'
let color = 'yellow'
const dog = {name, color}
console.log(dog)
4.3 字符串的解構(gòu)賦值
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
4.4 數(shù)值和布爾值的解構(gòu)賦值
解構(gòu)賦值時,如果等號右邊是數(shù)值和布爾值,則會先轉(zhuǎn)為對象
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
上面代碼中,數(shù)值和布爾值的包裝對象都有
toString屬性,因此變量s都能取到值
4.5 函數(shù)參數(shù)的解構(gòu)賦值
function add([x, y]){
return x + y
}
add([1, 2]) // 3
函數(shù)
add的參數(shù)表面上是一個數(shù)組,但在傳入?yún)?shù)的那一刻,數(shù)組參數(shù)就被解構(gòu)成變量x和y我們用Babel在線轉(zhuǎn)換工具把上述
ES6代碼轉(zhuǎn)化為ES5代碼看看,實(shí)際上就是講作為參數(shù)的數(shù)組分別結(jié)構(gòu)成了x和y再返回他們的和
"use strict";
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
function add(_ref) {
var _ref2 = _slicedToArray(_ref, 2),
x = _ref2[0],
y = _ref2[1];
return x + y;
}
add([1, 2]); // 3
4.6 其他
當(dāng)然對于解構(gòu)賦值還有很多新玩法,例如可以添加默認(rèn)值,這里阮一峰老師寫的很詳細(xì),請移步ES6標(biāo)準(zhǔn)入門
5 for...of
for...of語句創(chuàng)建一個循環(huán)來迭代可迭代的對象。在 ES6 中引入的for...of循環(huán),以替代for...in和forEach(),并支持新的迭代協(xié)議。for...of允許你遍歷 Arrays(數(shù)組), Strings(字符串), Maps(映射), Sets(集合)等可迭代的數(shù)據(jù)結(jié)構(gòu)等
我們先來看看以前的方法
for 循環(huán)
let arr = [1, 2, 3, 4, 5, 6]
for (let i = 1; i < arr.length; i++) {
console.log(arr[i])
}
缺點(diǎn):需要跟蹤計(jì)時器和退出條件
雖然 for 循環(huán)在循環(huán)數(shù)組時的確具有優(yōu)勢,但是某些數(shù)據(jù)結(jié)構(gòu)不是數(shù)組,因此并非始終適合使用 loop 循環(huán)
for...in循環(huán)
let arr = [1, 2, 3, 4, 5, 6]
for (const index in arr) {
console.log(arr[index])
}
缺點(diǎn): for...in 循環(huán)循環(huán)訪問所有可枚舉的屬性,意味著如果向數(shù)組的原型中添加任何其他屬性或者方法,這些屬性或方法也會出現(xiàn)在循環(huán)中,這就無意間浪費(fèi)了資源
forEach()循環(huán)
數(shù)組方法,只用于數(shù)組中,局限性大
for...of循環(huán)
const arrs = [1, 2, 3, 4, 5, 6]
for (const arr of arrs) {
console.log(arr)
}
// 可忽略索引
而且可以隨時退出或者停止for...of循環(huán)
const arrs = [1, 2, 3, 4, 5, 6]
for (const arr of arrs) {
if (arr % 2 === 0) {
continue
}
console.log(arr)
}
且不用擔(dān)心向?qū)ο笾刑砑有碌膶傩浴?strong>for...of 循環(huán)將只循環(huán)訪問對象中的值
6 展開運(yùn)算符
ES6中提供了展開運(yùn)算符為...
const dogs = ['dahuang', 'xiaohei', 'xiaobai']
console.log(...dogs) // dahuang xiaohei xiaobai
6.1 數(shù)組拼合
const dogs = ['dahuang', 'xiaohei', 'xiaobai']
const peoples = ['xiaoming', 'zhangsan', 'zhaosi', 'wangwu']
const animals = [...dogs, ...peoples]
console.log(animals)
// ['dahuang', 'xiaohei', 'xiaobai', 'xiaoming', 'zhangsan', 'zhaosi', 'wangwu']
這實(shí)際上已經(jīng)完成了以前拼合數(shù)組使用的concat()的功能
6.2 剩余參數(shù)
使用展開運(yùn)算符將數(shù)組展開為多個元素, 使用剩余參數(shù)可以將多個元素綁定到一個數(shù)組中
- 將變量賦數(shù)組值
const goods = [20, 200, 'pen', 'book', 'ruler']
const [price, totalCount, ...studyGoods] = goods
console.log(price, totalCount, studyGoods)
// 前兩個參數(shù)對應(yīng)前兩個,后面的作為數(shù)組傳入 studyGoods
- 可變剩余參數(shù)作為函數(shù)形參使用
function add (...numbers) {
let sum = 0
for (const number of numbers) {
sum += number
}
return sum
}
6.3 ES6 箭頭函數(shù)
箭頭函數(shù)是
ES6中的一大亮點(diǎn) ,下面看簡單的ES5中的函數(shù) 和ES6中的箭頭函數(shù)
ES5中的函數(shù)
var fn = function () { console.log('我是es5') }
ES6中的箭頭函數(shù)
const fn = () => { console.log('我是es6') }
// 等價于
const fn = () => console.log('我是es6')
就是講
ES5中的function()去掉,變成() =>,且當(dāng)函數(shù)體只有一句程序的時候,大括號也能省略
比較ES5中的函數(shù)和箭頭函數(shù):
- 前者可以使函數(shù)聲明或者函數(shù)表達(dá)式,但是后者只能是函數(shù)表達(dá)式,因此只在表達(dá)式有效的時候才能使用
- 什么是表達(dá)式有效時?
- 存儲在變量中
- 當(dāng)做參數(shù)傳遞給函數(shù)
- 存儲在對象屬性中
6.4 存儲在變量中的時候
其實(shí)上面的例子也說明了這點(diǎn),下面再舉兩個簡單的例子
const fn = numbers => `The pen are ${ numbers }`
// 調(diào)用
fn(200) // The pen are 200
const people = (name, age) => console.log(`${ name } is ${ age } years old`)
6.5 當(dāng)做參數(shù)傳遞給函數(shù)的時候
將函數(shù)表達(dá)式當(dāng)做參數(shù)傳遞給
map函數(shù),一般就是用于需要回調(diào)的函數(shù)
const people = ['zhangsan', 'zhaosi', 'wangwu'].map(name => name.toUpperCase())
6.6 存儲在對象屬性中的時候
const people = {
name: 'zhangsan',
age: 10,
say: () => console.log('hello')
}
console.dir(people.say) // say() 方法
6.7 箭頭函數(shù)與this
對于普通函數(shù),
this的值基于函數(shù)如何被調(diào)用, 對于箭頭函數(shù),this的值基于函數(shù)周圍的上下文, 換句話說,this的值和函數(shù)外面的this的值是一樣的
6.7.1 普通情況下的this
-
new對象,
const time = new Date() // 此時的this是Date()構(gòu)造函數(shù)的實(shí)例對象
- 上下文
window.setTimeout() // 函數(shù)`setTimeout()`是對象`window`下的方法,此時this指向window
- 指定的對象
const arr = Array.prototype.slice.call(arr1)
const arr = Array.prototype.slice.apply(arr1)
// call 或者 apply 第一個參數(shù)設(shè)置 this 指向,所以此時 this 指向 arr1
此外,this 指向還有很多其他的講究,詳細(xì)見You-Dont-Know-JS
6.7.2 箭頭函數(shù)與this
我們首先來看一個例子
Array.prototype.init = function () {
console.log(this)
setTimeout(function () {
console.log(this)
}, 1000)
}
這時候兩次打印出來的
this一樣嗎?執(zhí)行Array.prototype.init()打印結(jié)果出來看一下:很顯然,第一個打印出了
Array構(gòu)造函數(shù),第二個是Window,因?yàn)?code>setTimeout()是Window的方法,所以會改變this指向,那么使用箭頭函數(shù)看看
Array.prototype.init = function () {
console.log(this)
setTimeout( () => console.log(this), 1000)
}
Array.prototype.init()
這次就打印出了兩個
Array,this指向沒有發(fā)生變化
6.7.3 應(yīng)用場景
- 一些事件綁定之后需要操作原事件對象時防止
this改變- 用到一些構(gòu)造函數(shù)的方法的時候,防止該構(gòu)造函數(shù)的
this被改變- 等等......
7 Symbol
請移步我的另一篇博客ES6中的Symbol
8 class類
請移步我的另一篇博客ES6中的class關(guān)鍵字
9 Promise
請移步我的另一篇博客node-讀取文件方法封裝
10 Proxy
攔截代理,即在目標(biāo)對象外層包裹一層攔截,外接對對象的訪問都必須要先通過這層攔截,有點(diǎn)過濾的感覺,也有點(diǎn)像“門衛(wèi)”,小區(qū)進(jìn)門之前都要先過“門衛(wèi)”
10.1 語法
var proxy = new Proxy(target, handler)
10.2 參數(shù)
target:對象類型,表示需要被攔截的對象handler:對象類型,表示需要對這個對象target要做的攔截操作
10.3 例子
var proxy = new Proxy({}, {
get: function(target, property) {
return 35;
}
});
proxy.time // 35
proxy.name // 35
proxy.title // 35
如果
handler沒有設(shè)置任何攔截,那就等同于直接通向原對象
var target = {};
var handler = {};
var proxy = new Proxy(target, handler);
proxy.a = 'b';
target.a // "b"
11 Module
請移步我的另一篇博客ES6中Module語法與加載實(shí)現(xiàn)
12 參考文章
本文參考文章如下:
- 業(yè)界大佬阮一峰老師的ES6標(biāo)準(zhǔn)入門
- 一位道友的理解 JavaScript 中的 for…of 循環(huán)
- github上的You-Dont-Know-JS