文章目錄
- 簡介
- ECMAScript和JavaScript的關系
- let和const
- 解構賦值
- 陣列的擴展
- 函式的擴展
簡介
ECMAScript 6.0(以下簡稱 ES6)是 JavaScript 語言的下一代標準,正式發布與2015年6月,它的目標,是使得JavaScript語言可以用來撰寫復雜的大型應用程式,成為企業級開發語言,
今天我們將會講解一下ES6中引入的語法新特性,
ECMAScript和JavaScript的關系
1996年11月,JavaScript 的創造者 Netscape 公司,決定將 JavaScript 提交給國際標準化組織ECMA.
1997年, ECMA 發布262號標準檔案 ECMAScript 1.0,
ECMAScript 和 JavaScript 的關系是,前者是后者的規格,后者是前者的一種實作,
我們看一下ECMAScript的發行歷史:

從2015年ES2015,也就是ES6發布以來,ECMAScript以每年一個版本的發行速度發行到了ES2020,
后面的文章我們會講解一下這些新版本的ECMAScript的新特性,
let和const
ES6中引入了let和const,是為了解決之前的var變數的種種問題,
在ES6之前,JS中變數的作用域有兩種:全域作用域和函式作用域,
全域作用域很好理解,我們在瀏覽器控制臺或者 Node.js 互動終端中開始撰寫 JavaScript 時,即進入了所謂的全域作用域,
全域作用域的變數可以在任何其他作用域中訪問,
函式作用域就是定義在函式內部的變數,在函式內部都可以訪問到該變數,
這兩種作用域會有一些問題:
- 變數提升
var命令會發生”變數提升”現象,即變數可以在宣告之前使用,值為undefined.
// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;
- 變數覆寫
當我們在函式作用域使用全域變數的時候,如果函式作用域中定義了同樣名字的變數,不管是在哪里定義的,都會覆寫掉全域的變數,如下所示:
var tmp = new Date();
function f() {
console.log(tmp);
if (false) { var tmp = "hello world";
} }
f(); // undefined
- 變數泄露
變數泄露的意思是,我們本來只希望在小范圍作用域使用的變數,結果泄露到了范圍外面,如下所示:
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
~~
為了解決上面兩個問題,ES6引入了let和const,
這兩個都是塊級作用域,不同的是const定義的變數初始化之后就不能變化了,
什么是塊級作用域呢?類似于 if、switch 條件選擇或者 for、while 這樣的回圈體即是所謂的塊級作用域,或者更簡單一點使用大括號括起來的就叫做塊級作用域,
塊級作用域的最大好處就是不會產生作用域提升,如下所示:
~~~js
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
解構賦值
什么是解構賦值呢?
ES6 允許按照一定模式,從陣列和物件中提取值,對變數進行賦值,這被稱為解構,
如下所示:
let [a, b, c] = [1, 2, 3];
let [ , , third] = ["foo", "bar", "baz"];
let [x, , y] = [1, 2, 3];
let [head, ...tail] = [1, 2, 3, 4];
let [x, y] = [1, 2, 3];
解構賦值還可以設定默認值,我們來看下面的幾個例子:
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 = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null
如果解構的默認值是一個函式,那么可以觸發惰性賦值:
function f() {
console.log('aaa');
}
let [x = f()] = [1];
上面的例子中,f函式將不會被執行,
除了結構變數之外,還可以結構物件:
let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
解構還支持嵌套的結構:
let obj = { p: [ 'Hello', { y: 'World' } ] };
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
解構賦值有兩個非常重要的作用,
第一就是交換變數:
let x = 1;
let y = 2;
[x, y] = [y, x];
我們就可以不再使用中間變數,直接進行兩個變數值的互動,
第二個作用就是從函式中回傳多個值:
// 回傳一個陣列
function example() { return [1, 2, 3]; }
let [a, b, c] = example();
// 回傳一個物件
function example() { return { foo: 1, bar: 2 }; }
let { foo, bar } = example();
//提取JSON資料
let jsonData = { id: 42, status: "OK", data: [867, 5309] };
let { id, status, data: number } = jsonData;
陣列的擴展
ES6中的Array.from方法用于將下面兩類物件轉為真正的陣列:
- 類似陣列的物件(array-like object)
- 可遍歷(iterable)的物件(包括ES6新增的資料結構Set和Map),
什么是類似陣列物件呢?
所謂類似陣列的物件,本質特征只有一點,即必須有length屬性,因此,任何有length屬性的物件,都可以通過Array.from方法轉為陣列,
下面的變數就是類陣列變數:
let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 };
這個類陣列物件怎么轉換成為陣列呢?
// ES5的寫法
var arr1 = [].slice.call(arrayLike);
// ['a', 'b', 'c']
// ES6的寫法 let arr2 = Array.from(arrayLike);
// ['a', 'b', 'c']
我們看下通常的使用場景:
// NodeList物件
let ps = document.querySelectorAll('p');
Array.from(ps).forEach(function (p) { console.log(p); });
// arguments物件
function foo() { var args = Array.from(arguments);
// ...
}
什么是可遍歷物件呢?
只要是部署了Iterator介面的資料結構,都叫做可遍歷物件,
我們看下下面的例子:
Array.from('hello') // ['h', 'e', 'l', 'l', 'o']
let namesSet = new Set(['a', 'b'])
Array.from(namesSet) // ['a', 'b']
同時還引入了擴展運算子(…),通過擴展運算子,也可以很方便的轉換為陣列物件:
function foo() { var args = [...arguments]; } // arguments物件
[...document.querySelectorAll('div')] // NodeList物件
Array.from方法還可以接收第二個引數,用來對陣列中的元素進行操作:
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);
Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]
Array.of方法可以很方便的創建新的陣列:
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
函式的擴展
ES6,可以支持函式的默認值了:
function log(x, y = 'World') { console.log(x, y); }
function Point(x = 0, y = 0) { this.x = x; this.y = y; }
函式的默認值可以和解構賦值默認值組合起來使用:
function foo({x, y = 5}) { console.log(x, y); }
foo({}) // undefined, 5
foo({x: 1}) // 1, 5
foo({x: 1, y: 2}) // 1, 2
foo() // TypeError: Cannot read property 'x' of undefined
接下來,我們看一個復雜的例子:
// 寫法一
function m1({x = 0, y = 0} = {})
{ return [x, y]; }
// 寫法二
function m2({x, y} = { x: 0, y: 0 })
{ return [x, y]; }
我們來看一下,上面的兩種寫法有什么不同呢?
當函式沒有引數的情況:
m1() // [0, 0]
m2() // [0, 0]
當x和y都有值的情況:
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]
當x有值,y無值的情況 :
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]
當x和y都無值的情況:
m1({}) // [0, 0];
m2({}) // [undefined, undefined]
m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]
看出區別了嗎? m1的解構賦值,對于x,y來說是有默認值0的,而m2的解構賦值對于x,y來說是沒有默認值的,
本文作者:flydean程式那些事
本文鏈接:http://www.flydean.com/ecmascript-6-startup/
本文來源:flydean的博客
歡迎關注我的公眾號:「程式那些事」最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/112540.html
標籤:其他
上一篇:VUE 3.0初體驗
下一篇:日常學習之webpack①
