ES6能夠說是一個泛指,指5.1版本之後的JavaScript
的下一代標準,涵蓋了ES2015,ES2016,ES2017
等;亦指下一代JavaScript語言。javascript
嗯~ES6的語法有什麼好談的,無聊了吧?java
確實,語法糖的東西真的是學起來如嚼蠟 -- 淡無味;可是要用別人的東西來開發的,你學仍是學呢?git
因此,仍是簡單談下吧...es6
本次的ES6語法的彙總總共分爲上、中、下三篇,本篇文章爲上篇。github
var
是以前就有的了,在這裏提出來主要是爲了比較其和let與const
。數組
1. 塊級做用域函數
for(var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 輸出3個3
}, 0)
}
複製代碼
解析:變量i是var
聲明的,在全局範圍內是都有效,全局只有一個變量i。每次循環,變量的值會發生改變。循環內的i是指向全局的i。優化
for(let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 輸出0, 1, 2
}, 0)
}
複製代碼
解析:變量i是let
聲明的,當前的i只在本輪循環有效,因此每次循環的i其實都是一個新變量。JavaScript引擎內部會記住上一輪的值,初始化本輪的變量i時,就在上一輪循環的基礎上進行計算。ui
2. 不存在變量提高this
console.log(a); // undefined
var a = 100;
複製代碼
var
命令會發生變量提高現象,即變量能夠在聲明以前使用,值爲undefined
;而let
糾正了這種行爲,不能產生變量提高。
console.log(a); // 報錯
let a = 100;
複製代碼
3. 暫時性死區
只要塊級做用域內,存在let
命令,它所聲明的變量就綁定(binding)在這個區域,再也不受外部影響。
如:
var temp = 123;
if(true) {
temp = 'abc'; // 引入錯誤
let temp;
}
複製代碼
在上面中,if後面的大括號內容就造成了一個區域。而temp此時是找不到外層的,由於內部有個temp
且你在內部let temp
聲明前賦值了。
在看一個隱晦的例子:
function bar(x = y, y = 2) {
return [x, y]
}
bar(); // 報錯
複製代碼
在上面的例子中bar裏面進行賦值操做的時候,就產生了一個封閉的區域了,能夠認爲x 和 y經過let聲明
,但是上面的問題是,x = y
的引用在y = 2
的聲明以前。
能夠修正以下:
function bar(y = 2, x = y) {
return [x, y];
}
bar(); // [2, 2]
複製代碼
4. 不可重複聲明
var a = 100;
var a = 1000;
console.log(a); // 1000
複製代碼
let a = 100;
let a = 1000; // 報重複聲明錯誤
複製代碼
5. ES6聲明的變量不會掛在頂層對象
嗯~ES6變量的聲明是指哪些聲明呢?
指let, const, import, class
聲明。
而var, function
聲明是ES6以前的。
因此目前JavaScript
有六種聲明變量的方式了~
var job = 'teacher';
console.log(window.job); // teacher
複製代碼
let job = 'teacher';
console.log(window.job); // undefined
複製代碼
let
能夠先聲明稍後賦值;而const
聲明以後必須立馬賦值,不然會報錯let a;
a = 100; // this is ok
複製代碼
const a; // 報沒初始化數據的錯誤
複製代碼
const
聲明瞭簡單的數據類型就不能更改了;聲明瞭引用類型(數組,對象等),指針指向的地址不能更改,可是內部的數據能夠更改的const str = 'this is a string';
str = 'this is another string'; // 報了個「給不變的變量分配值」的錯誤
複製代碼
const obj = {
name: 'jia'
}
obj.name = 'ming'; // this is ok
obj = {}; // 報了個「給不變的變量分配值」的錯誤
複製代碼
let
使用場景:變量,用以代替var
const
使用場景:常量、聲明匿名函數、箭頭函數的時候。
// 常量
const PI = 3.14;
// 匿名函數
const fn1 = function() {
// do something
}
// 箭頭函數
const fn2 = () => {
// do something
}
複製代碼
解構能夠理解就是一個做用:簡化你變量賦值的操做。
let [name, job] = ['jiaming', 'teacher'];
console.log(name); // jiaming
複製代碼
本質上,這種寫法屬於模式匹配,只要等號兩邊的模式相同(重點),左邊的變量就會被賦予對應的值。再好比:
let [ , , third] = ["foo", "bar", "baz"];
console.log(third); // "baz"
let [head, body, ...tail] = [1, 2, 3, 4, 5];
console.log(tail); // [3, 4, 5]
複製代碼
也可使用默認值。可是默認值生效的前提是:ES6內部使用嚴格相等運算符(===),判斷一個位置是否有值。因此,只有當一個數組成員嚴格等於undefined,默認值纔會生效。
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [z = 1] = [undefined];
console.log(z); // 1
let [k = 1] = [null];
console.log(k); // null
複製代碼
const state = {
name: 'jiaming',
job: 'teacher'
};
let {
name,
job
} = state;
// 上面的場景很熟悉吧
console.log(job); // teacher
複製代碼
上面的例子若是寫具體的話,是這樣的:
const state = {
name: 'jiaming',
job: 'teacher'
};
let {
name: name, // 第一個name是匹配模式,第二個name纔是變量,二者同名簡化成一個便可
job: job
} = state;
複製代碼
咱們來改寫下:
const state = {
name: 'jiaming',
job: 'teacher'
};
let {
name: job,
job: name
} = state;
console.log(job); // jiaming
複製代碼
對象也可使用默認值,可是前提是:對象的屬性值嚴格等於undefined
。
以下:
var {x = 3} = {x: undefined};
console.log(x); // 3
var {y = 3} = {y: null};
console.log(y); // null
複製代碼
字符串之因此可以被解構賦值,是由於此時字符串被轉換成了一個相似數組的對象。
const [a, b, ...arr] = 'hello';
console.log(arr); // ["l", "l", "o"]
複製代碼
let {length: len} = 'hello';
console.log(len); // 5
複製代碼
解構賦值時,若是等號右邊是數值和布爾值,則會先轉換爲對象(分別是基本包裝類型Number和基本包裝類型Boolean)。不過這種場景用得很少~
let {toString: s} = 123;
console.log(s); // function toString() { [native code] }
console.log(s === Number.prototype.toString); // true
複製代碼
let {toString: s} = true;
console.log(s === Boolean.prototype.toString); // true
複製代碼
解構賦值的規則是,只要等號右邊的值不是對象或數組,就先將其轉爲對象。因爲undefined和null沒法轉爲對象,因此對它們進行解構賦值,都會報錯
。
1. 交換兩變量值
let [a, b] = ['reng', 'jia'];
[a, b] = [b, a];
console.log(b); // 'reng'
複製代碼
2. 將字符串轉換爲數組
let [...arr] = 'reng';
console.log(arr); // ["r", "e", "n", "g"]
console.log(arr.splice(0, 2)); // ["r", "e"] 返回刪除的數組(能使用數組的方法了)
複製代碼
針對字符串擴展這個,我的感受模版字符串使用的頻率比較高。模版字符串解放了拼接字符串帶來的繁瑣操做的體力勞動。
let name = 'jiaming';
let str = 'Hello! My name is '+ name + '. Nice to meet you!';
let strTemp = `Hello! My name is ${ name }. Nice to meet you!`
複製代碼
對於新增的字符串方法,能夠記下下面這幾個:
留意下在Number
對象上提供的新方法:
Number.isNaN(NaN) // true
Number.isNaN(15) // false
複製代碼
關於Math
對象上的方法,遇到要用到時候,查API吧,否則記太多,腦瓜子會疼~
ES6引入rest參數(形式是...變量名
),用於獲取多餘的參數,這樣就不須要使用arguments
對象了。rest參數搭配的變量是一個數組(arguments是一個類數組來的),該變量將多餘的參數放入數組中。
arguments對象是一個類數組,還得經過Array.prototype.slice.call(arguments)
將其轉換爲真數組;而rest參數直接就可使用數組的方法了。
function add(...arr) {
console.log(arr); // [2, 5, 3]
let sum = 0;
for(var val of arr) {
sum += val;
}
return sum;
}
console.log(add(2, 5, 3)); // 10
複製代碼
ES6容許使用「箭頭」(=>
)定義函數。
const f = v => v; // 注意是有返回值return的啊
// 等同於
const f = function (v) {
return v;
}
複製代碼
若是箭頭函數的代碼塊部分多於一條語句,就要使用大括號將它們括起來,而且使用return
語句返回結果。
const sum = (num1, num2) => num1 + num2;
// 等價於,使用了大括號,那箭頭函數裏面就要使用return了
const sum = (num1, num2) => { return num1 + num2 }
// 等價於
const sum = function(num1, num2) {
return num1 + num2
}
複製代碼
使用箭頭函數注意點:
this
對象,就是定義所在的對象,而不是使用時所在的對象。new
命令,不然會拋出一個錯誤。arguments
對象,該對象在函數體內不存在的,若是要用,能夠用rest參數代替。yield
命令,所以箭頭函數不能用做Generator函數。function foo() {
setTimeout(() => {
console.log('id:', this.id); // id: 42
}, 100);
}
var id = 21;
foo.call({ id: 42 });
複製代碼
// 錯誤使用箭頭函數的例子
const cat = {
lives: 9,
jumps: () => { // 箭頭函數的錯誤使用,由於對象不構成單獨的做用域
this.lives--; // this 指向window
}
}
var button = document.getElementById('press'); // 一個節點對象
button.addEventListener('click', () => { // 箭頭函數的this指向window
this.classList.toggle('on');
});
// 箭頭函數改爲`function`匿名函數指向就正確了。
複製代碼
箭頭函數適合處理簡單的計算,若是有複雜的函數體或讀寫操縱不建議使用,這樣能夠提升代碼的可讀性。
關於尾遞歸和其優化能夠直接看阮先生的文檔
假設有這麼一個需求,須要對二維數組的元素進行反轉並被1減。咱們來看下下面代碼,哪一個能實現此需求呢?
// 代碼一
const A = [[0,1,1],[1,0,1],[0,0,0]];
const flipAndInvertArr = function(A) {
A.map(item=>{
item.reverse().map(r=>1-r)
})
}
複製代碼
// 代碼二
const A = [[0,1,1],[1,0,1],[0,0,0]];
const flipAndInvertArr = A=> A.map(res =>res.reverse().map(r => 1 - r));
複製代碼
運行以後,發現代碼二是能實現需求的:
let resultArr = flipAndInvertArr(A);
console.log(resultArr); // [[0, 0, 1], [0, 1, 0], [1, 1, 1]]
複製代碼
嗯~上面已經提到過,箭頭函數體加上大括號後,是須要本身手動return的~
咱們來改寫下代碼一,以便符合需求:
const A = [[0,1,1],[1,0,1],[0,0,0]];
const flipAndInvertArr = function(A) {
return (A.map(item=>{
return item.reverse().map(r=>1-r)
}))
}
let result = flipAndInvertArr(A);
console.log(result); // [[0, 0, 1], [0, 1, 0], [1, 1, 1]]
複製代碼
驚喜不,意外不~
本次的ES6語法的彙總總共分爲上、中、下三篇,本篇文章爲上篇。
文章首發在github上--談談ES6語法(彙總上篇)。更多的內容,請戳個人博客進行了解,能留個star就更好了💨