ES6基本語法
ES6是什麼?
JavaScript的第六版,在ES5的基礎上增加了許多特性:箭頭函式、字串插值、代理、生成器、結構賦值、塊級作用域等等。
一、let和const
1.作用:宣告變數
ES6
中明確規定,如果區塊中存在 let
和 const
命令,則這個區塊對這些命令宣告的變數從一開始就形成封閉作用域。只要在宣告之前就使用這些變數,就會報錯(暫時性死區)。
2.let使用注意:
- 作用域只侷限於當前程式碼塊
- 使用
let
宣告的變數作用域不會被提升 - 在相同的作用域下不能宣告相同的變數
-
for
迴圈體現let
的父子作用域
3.const使用注意:
const
二、解構賦值
1.基本用法
let [name, age, sex] = ['李四', 20, '女']; console.log(name);// 李四 console.log(age);// 20 console.log(sex);// 女
2.物件的結構賦值
let { name, age, friends, pet } = { name: '張三', age: 55, friends: ['lulu', '王五'], pet: { name: '土豆', age: 5 } }; console.log(name);// 張三 console.log(age);// 55 console.log(friends);// ["lulu", "王五"] console.log(pet);// {name: "土豆", age: 5}
let { name: str } = { name: '張三' }; console.log(name);// console.log(str);// 張三
3.陣列的解構賦值
let [arr1, [arr2, arr3, [arr4, arr5]]] = [1, [2, 3, [4, 5]]]; console.log(arr1, arr2, arr3, arr4, arr5); // 1 2 3 4 5
let [arr1] = []; console.log(arr1); // undefined
let [a, , c] = [1, 2, 3]; console.log(a);// 1 console.log(c);// 3
4.基本型別的解構賦值
let [a, b, c, d, e] = '我是中國人'; console.log(a);// 我 console.log(b);// 是 console.log(c);// 中 console.log(d);// 國 console.log(e);// 人
三、資料集合-set
類似於陣列,但是成員是唯一的,沒有重複。
1.建立一個集合
let set = new Set(['張三', '李四', '王五', '張三', '李四']); console.log(set); //{"張三", "李四", "王五"} console.log(Array.from(set)); // ["張三", "李四", "王五"]
2.一個屬性
console.log(set.size); //3
3.四個方法
//add console.log(set.add('劉德華').add('LHH')); //{"張三", "李四", "王五", "劉德華", "LHH"} console.log(set); //{"張三", "李四", "王五", "劉德華", "LHH"} //delete console.log(set.delete('張三'));// true console.log(set.delete('李四'));// true console.log(set); //has console.log(set.has('張三'));// true console.log(set.has('張三1'));// false //clear console.log(set.clear()); // undefined console.log(set); // {}
4.keys values
console.log(set.keys());// SetIterator {"張三", "李四", "王五"} console.log(set.values());// SetIterator {"張三", "李四", "王五"}
四、資料集合-map
類似於物件,也是鍵值對集合,但“鍵”的範圍不限於字串,各種型別的值(包括物件)都可以當作鍵.
1. 建立一個Map
let obj1 = { a: 1 }, obj2 = { b: 2 }; const map = new Map([ ['name', '張三'], ['age', 18], ['sex', '男'], [obj1, '今天天氣很好'], [obj2, '適合敲程式碼'], [ [1, 2], 'hhh' ] ]); console.log(map); console.log(map.size);
2.set和get
map.set('friends', ['趙六', '力氣']).set(['dog'], '小花'); console.log(map); console.log(map.get('name')); console.log(map.get(obj1));
3.delete
map.delete(obj1); console.log(map.delete('xxxx')); console.log(map);
4.has
console.log(map.has(obj1));// true console.log(map.has(obj2));//true
5.clear
map.clear(); console.log(map);// {}
6.keys() values() entries()
console.log(map); console.log(map.keys()); console.log(map.values()); console.log(map.entries());
7.遍歷
map.forEach(function(value, index) { console.log(index + ':' + value); })
8.注意事項
map.set({}, '呵呵呵呵呵'); map.set({}, '哈哈哈哈'); console.log(map); console.log({} === {});
五、Symbol
1.定義
let str1 = Symbol(); let str2 = Symbol(); console.log(str1 === str2); // false console.log(typeof str1);// symbol console.log(typeof str2);// symbol
2.描述
let str3 = Symbol('name'); let str4 = Symbol('name'); console.log(str3);// Symbol(name) console.log(str4);// Symbol(name) console.log(str3 === str4); // false
3. 物件的屬性名
const obj = {}; obj.name = '張三'; obj.name = '李四'; obj[Symbol('name')] = '張三'; obj[Symbol('name')] = '李四'; let a = Symbol('aa'); let b = Symbol('bb'); obj[a] = '王五' obj[b] = 'kk' console.log(obj); console.log(Object.getOwnPropertySymbols(obj));// 獲取指定物件的所有Symbol屬性名 console.log(Reflect.ownKeys(obj));// 返回所有型別的鍵名,包括常規鍵名和Symbol鍵名
注意, Symbol
函式前不能使用 new
命令,因為 Symbol
是一個原始型別的值,不是物件,所以也不能新增屬性。
4.Symbol.for() 和 Symbol.keyfor()
var s1 = Symbol.for('foo'); var s2 = Symbol.for('foo'); s1===s2;// true
上面程式碼中, s1
和 s2
都是Symbol的值,但它們都是同樣引數的 Symbol.for
方法生成的,所有實際上是同一個值。
Symbol.for()
與 Symbol()
這兩種寫法都會生成新的 Symbol
。它們的區別是,前者會被登記在全域性環境中供搜尋,而後者不會。Symbol.for()不會再每次呼叫時都返回一個新的 Symbol
型別的值,而是會先檢查給定的 key
是否已經存在,如果不存在才會新建一個值,比如,如果呼叫Symbol.for('cat')30次,每次都會返回同一個 Symbol
值,但是呼叫Symbol('cat')30次則會返回30個不同的 Symbol
值。
Symbol.keyFor()方法返回一個已登記的Symbol型別值得key
var s1 = Symbol.for("foo"); Symbol.keyFor(s1);// "foo" var s2 = Symbol("foo"); Symbol.keyFor(s2);// undefined
注: Symbol.for
為 Symbol
值登記的名字是全域性環境的,可以在不同的 iframe
或 service worker
中取到同一個值。
iframe = document.createElement('iframe'); iframe.src = String(window.location); document.body.appendchild(iframe); iframe.contentWindow.Symbol.for('foo') === Symbol.for('foo');// true
六、class的基本運用
1.建構函式
function Person(name, age) { this.name = name; this.age = age; } Person.prototype = { constructor: Person, print(){ console.log('我叫' + this.name + ',今年' + this.age + '歲'); } }; //或 //Person.prototype.print = function() { //console.log('我叫' + this.name + ',今年' + this.age + '歲'); //} let person = new Person('張三', 19); console.log(person); person.print();
2. 通過class面向物件
class Person { constructor(name, age) { this.name = name; this.age = age; } print() { console.log('我叫' + this.name + ',今年' + this.age + '歲'); } } let person = new Person('張三', 19); console.log(person); person.print();
3.class實現繼承
class Animal { //建構函式 constructor(props) { this.name = props.name || '未知'; } eat() { alert(this.name + "在吃東西..."); } } //class繼承 class Bird extends Animal { //建構函式 constructor(props) { //呼叫實現父類的建構函式 super(props); this.type = props.type || "未知"; } fly() { alert(this.name + "在飛..."); } } var myBird = new Bird({ name: '鸚鵡' }) myBird.eat()// 鸚鵡在吃東西... myBird.fly()// 鸚鵡在飛...
七、內建物件擴充套件
1. 模板字串
let str = '適合敲程式碼!'; let className = 'test'; let html = `<html> <head></head> <body> <p>今天的天氣很好!</p> <div class="${className}">${str}</div> </body> </html>`; console.log(html);
2. 陣列的擴充套件
Array.from
// 在body中寫了幾個li節點 let allLis = document.querySelectorAll('li'); console.log(allLis);// NodeList(6) [li, li, li, li, li, li] console.log(Array.isArray(allLis));// false console.log(Array.from(allLis));// [li, li, li, li, li, li] console.log(Array.isArray(Array.from(allLis)));// true
Array.of
console.log(Array.of(1, 2, 3, 4));// [1, 2, 3, 4] console.log(Array.of('張三', '李四', '王五'));// ["張三", "李四", "王五"]
3. 物件的擴充套件
key
和 value
是一樣的,寫一個就夠了
let name = '張三'; let age = 18; let person = { name, age }; console.log(person);// {name: "張三", age: 18}
Object.assign()
let obj1 = { name: '張三' }; let obj2 = { age: 18 }; let obj3 = { sex: '男' }; let obj4 = { friends: '李四' }; let obj = {}; Object.assign(obj, obj1, obj2, obj3, obj4); console.log(Object.assign(obj, obj1, obj2, obj3, obj4)); // {name: "張三", age: 18, sex: "男", friends: "李四"} console.log(obj);// {name: "張三", age: 18, sex: "男", friends: "李四"}
延展操作符
let str = '今天的天氣很好!'; let strArr = [...str]; console.log(strArr);// ["今", "天", "的", "天", "氣", "很", "好", "!"]
let student = { name: '張三', age: 18, sex: '男' } < Person {...student}/>
let myArr = [1, 2, 10, '張三', 20, 2, 1]; console.log(new Set(myArr));// {1, 2, 10, "張三", 20} console.log([...new Set(myArr)]);// [1, 2, 10, "張三", 20]
八、函式的擴充套件
1. 形參設定預設值
function sum(num1 = 20, num2 = 10) { console.log(num1 + num2); } /* function sum(num1, num2) { num1 = num1 || 10; num2 = num2 || 10; console.log(num1 + num2); } */ sum(10, 30);// 40 sum();// 30
2.引數形式 延展操作符
function sum(name, sex, ...nums) { let result = 0; console.log(name); console.log(sex); for (let value of nums) { result += value; } return result; } /* function sum() { let result = 0; for(let value of arguments){ result += value; } return result; } */ console.log(sum('張男', '男', 10, 20, 30, 50)); // 張男 // 男 // 110
3.箭頭函式 () => {}
let sum = (num1, num2)=>{ return num1 + num2;}; console.log(sum(100, 300));// 400
let nameArr = ['張三', '李四', '王五']; nameArr.forEach((value, index) => { console.log(index + ':' + value); }); // 0:張三 // 1:李四 // 2:王五
this的指向不同
function demo() { setTimeout(function() { console.log(this); }, 500); setTimeout(() => { console.log(this); }, 1000); } let obj = { a: 1 }; demo.call(obj); // Window // {a: 1}
箭頭函式的幾個注意事項:
- 函式體內的
this
物件就是定義時所在的物件,而不是使用時所在的物件; - 不可以當作建構函式。也就是不可以使用
new
命令,否則報錯; - 不可以使用
arguments
物件,該物件在函式體內不存在;可以rest
引數代替(...引數); - 不可以使用
yield
命令,因此箭頭函式不能用作Generator
函式;
九、Iterator遍歷器和for..of迴圈
Iterator
作用:一是為各種資料結構提供統一的、簡便的訪問介面;二是使得資料結構的成員能夠按某種次序排列;三是 ES6
建立了一種新的遍歷命令—— for...of
迴圈, Iterator
介面主要供 for...of
消費
模擬next方法返回值得例子:
var it = makeIterator(['a', 'b']); console.log(it.next());// {value: "a", done: false} console.log(it.next());// {value: "b", done: false} console.log(it.next());// {value: undefined, done: true} function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? { value: array[nextIndex++], done: false } : { value: undefined, done: true } } } }
具備Iterator介面的資料結構如下:
Array
Map
Set
String
TypedArray
函式的 arguments
物件 NodeList
物件
下面例子是陣列的 Symbol.iterator
屬性:
let arr = ['a', 'b', 'c']; let iter = arr[Symbol.iterator](); console.log(iter.next());// {value: "a", done: false} console.log(iter.next());// {value: "b", done: false} console.log(iter.next());// {value: "c", done: false} console.log(iter.next());// {value: undefined, done: true}
注意:物件( Object
)之所以沒有預設部署 Iterator
介面,是因為物件屬性的遍歷先後順序是不確定的。
for...of迴圈
一個數據結構只要部署了 Symbol.iterator
屬性,就被視為具有 Iterator
介面,就可以用 for...of
迴圈它的成員。
注意:有些資料結構是在現有資料結構的基礎上計算生成的,比如 ES6
的陣列、 Set
、 Map
都部署了一下三個方法,呼叫後都返回遍歷器物件
-
entries()
返回一個遍歷器物件,用於遍歷[鍵名,鍵值]組成的陣列。對於陣列,鍵名就是索引值;對於Set
,鍵名與鍵值相同。Map
結構的Iterator
介面預設就是呼叫entries
方法 -
keys()
返回一個遍歷器物件,用於遍歷所有的鍵名 -
values()
返回一個遍歷器物件,用於遍歷所有的鍵值