ES6-阮一峰
ES6補充
0.瀏覽器中的ES6
方法一:引入文件相關(guān)js文件
<script src="traceur.js"></script>
<script src="bootstrap.js"></script>
<script type="module">
//code 這里寫你的jsx代碼
</script>
注意:嚴格模式('use strict'),注意格式。
1.let和const
優(yōu)先使用常量(const)。let 定義變量 ,有塊級別作用域(只在本塊有用,不會影響其他的)
注意:在同一個塊級作用域中,let不能重復(fù)定義同一變量。
const a = 'Tab';
alert(a);
// 1.不能重復(fù)定義
// 2.常量不能修改
2.模板引擎(字符串拼接)
新的“字符串拼接”方法比較簡單,沒有繁瑣的加號和引號,只需要在所需要的字符串“邊界”加上``即可。
var str1 = `我是${name},今年${age}歲,性別${sex}的了,愛好${hobby}`; //注意此處有兩個“ `` ”
var str2 = '我是'+name+',今年'+age+'歲,性別'+sex+',愛好'+hobby+''; //這個是原來的寫法
3. 解構(gòu)賦值
就根據(jù)“對應(yīng)”賦值,請看以下幾個例子:
'use strict';
let a = 12;
let b = 5;
let c = 8;
let [a,b,c] = [12,5,8];
console.log(a,b,c); //12 5 8
json格式的賦值
let {a,b,c} = {a:12,b:5,c:8};
let [a,[b,c],d] = [12,[1,3],8];
與順序無關(guān),與結(jié)構(gòu)有關(guān)(左右結(jié)構(gòu)一致):
let {a,b,c} = {b:5,a:12,c:8};
console.log(a,b,c); //12 5 8
應(yīng)用,我們現(xiàn)在利用jsonp獲取了一組數(shù)據(jù)
let json = {
q:"aaa",
p:false,
s:["aaa"]
};
let {s,q} = json;
console.log(s,q); //s為數(shù)組的數(shù)據(jù),q為字符串a(chǎn)aa
解構(gòu)賦值的默認值問題
let {time=1000,id=0} = {};
console.log(time,id); // 1000 0
4.擴展運算符
數(shù)組或者對象的深淺拷貝問題,今天我們就利用es6的三個點來處理下。上面的代碼就是arr2與arr公用一段內(nèi)存地址,所以導(dǎo)致srr2數(shù)據(jù)改變的時候arr也必然會變的。這就是淺拷貝。
var arr = [12,5,8];
arr2 = arr;
arr2.pop();
alert(arr); // 12 5
那么我們下面就簡單的說幾種深度復(fù)制數(shù)組方式。 方式一:利用for循環(huán)把原數(shù)組的每一項都遍歷,然后扔到新的數(shù)組中。
var arr = [12,5,8];
var arr2 =[];
for(var i = 0;i < arr.length; i++){
arr2.push(arr[i]);
}
arr2.pop();
alert(arr); // 12 5 8
方式二:利用Array.from(原數(shù)組);
var arr = [12,5,8];
var arr2 = Array.from(arr);
arr2.pop();
console.log(arr2); // 12 5
console.log(arr); // 12 5 8
附加:Array.from用法
Array.from(arr, [mapfn], [thisArg]) arr:偽數(shù)組或者可以遍歷的對象(具有l(wèi)ength屬性)。 length 決定數(shù)組會轉(zhuǎn)化成什么樣。from會根據(jù) length 屬性創(chuàng)建新的數(shù)組。 mapFn:類似于 array.map 方法,對數(shù)組元素進行操作后返回數(shù)組 thisArg: 對于 this 關(guān)鍵字的指向。
用途
1.將具有l(wèi)ength的對象轉(zhuǎn)化為數(shù)組
2.數(shù)組深復(fù)制
3.計算字符串真實長度Array.from(string).length
4.可以控制函數(shù)執(zhí)行的次數(shù)
Array.from({length:3}, () => {
console.log('0');
});
方式三:擴展運算符
var arr = [12,5,8];
var arr2 = [...arr];
我們知道函數(shù)的參數(shù)是一個集合(arguments)并不是一個真正的數(shù)組。那么我們怎么才能在這個arguments中加一項呢??
function show(...arr){
arr.push(8);
console.log(arr);
}
show(12,5); //12 5 8
5. Map對象
ES6提供了新的數(shù)據(jù)結(jié)構(gòu)Map,Map結(jié)構(gòu)提供了“值—值”的對應(yīng),是一種更完善的Hash結(jié)構(gòu)實現(xiàn)。如果你需要“鍵值對”的數(shù)據(jù)結(jié)構(gòu),Map比Object更合適。它類似于對象,也是鍵值對的集合,但是“鍵”的范圍不限于字符串,各種類型的值(包括對象)都可以當(dāng)作鍵。{"b" => "banana"}并且每一項都包含了key和value 我們來新建一個Map對象,并為其賦值:
let map = new Map();
map.set('a','apple');
map.set('b','banana');
console.log(map);
//Map {"a" => "apple", "b" => "banana"}
console.log(map.get('b'));
map.delete("a");
console.log(map.size); //1
console.log(map.length); //undefined
獲取Map對象里面的值(map.get();)
刪除Map對象里面的值(map.delete();)
獲取Map對象的“長度”:(map.size());
迭代器對象:map.entries()
let map = new Map();
map.set('a','apple');
map.set('b','banana');
console.log(map.entries()); // MapIterator {["a", "apple"], ["b", "banana"]}
// MDN說明: Map.prototype.entries() 這個方法返回一個新的迭代器對象,對于每一個元素包含鍵值對(在這個map對象中按照插入的順序輸出)
// The entries() method returns a new Iterator(迭代器) object that contains the [key, value] pairs for each element in the Map object in insertion order.
//關(guān)于迭代器(Iterator)和生成器(generator) 在ES6中新引入,單獨學(xué)習(xí)。
// 迭代器中的元素不能直接讀取,可以通過下面兩種方法進行讀取。
// 方法一:
let arr = [];
let map = new Map();
for(let [key, val] of map.entries()) {
arr.push([key, val]);
}
// 方法二:
var map = new Map();
Array.from(map);
遍歷Map對象(for...of... )
let map = new Map();
map.set('a','apple');
map.set('b','banana');
for(let name of map){
console.log(name); //["a", "apple"] ["b", "banana"]
}
//循環(huán)出來的是以數(shù)組套鍵值對的方式
如果我們只要Map中的“值”怎么辦?
let map = new Map();
map.set('a','apple');
map.set('b','banana');
for(let val of map.values()){
console.log(val); //apple banana
}
如果我們只要Map中的“鍵(key)”怎么辦?
let map = new Map();
map.set('a','apple');
map.set('b','banana');
for(let key of map.keys()){
console.log(key); // a b
}
如果我們只要Map中的“鍵 --- 值”怎么辦?
let map = new Map();
map.set('a','apple');
map.set('b','banana');
for(let [key,value] of map.entries()){
console.log(key,value); //a apple b banana
}
6. for循環(huán)
a) for ... in ...循環(huán)
//循環(huán)數(shù)組
let arr = [12,5,8];
for(let i = 0;i<arr.length;i++) {
console.log(i); //0 1 2
console.log(arr[i]); //12 5 8
}
let arr = [12,5,8];
for(let i in arr) {
console.log(i); //0 1 2
console.log(arr[i]); //12 5 8
}
//循環(huán)json數(shù)據(jù)
let json = {a:12,b:5,c:8};
for(let name in json){
console.log(name); //a b c
console.log(json[name]); //12 5 8
}
b) for ... of ...循環(huán)
//循環(huán)數(shù)組
let arr = [12,5,8];
for(let name of arr){
console.log(name); // 12 5 8
}
//循環(huán)json數(shù)據(jù)
let json = {a:'apple',b:'banana'};
for(let name of json){
console.log(name); //error
}
//報錯,因為不能用for ...of...來循環(huán)json數(shù)據(jù)
c) 刪除json的某一條數(shù)據(jù)
let json = {a:12,b:5};
delete json.a;
console.log(json); // b:5
7. 箭頭函數(shù)
ES6標準新增了一種新的函數(shù):Arrow Function(箭頭函數(shù))。
我們先回顧下ES5函數(shù)定義與調(diào)用:
var show = function(){
alert(12);
};
show(); // 12
const show = (num1, num2) =>{
alert(num1 + num2);
};
show(1, 11); // 12
a) 函數(shù)有返回值
//ES5函數(shù)寫法
var sum = function(a,b){
return a+b;
}
alert(sum(12,5));
//ES6函數(shù)寫法
let sum = (a,b) => {
return a+b;
}
alert(sum(12,5));
//進化一下 --- 省略花括號
let sum = (a,b) => a+b;
alert(sum(12,5));
b) 參數(shù)是1個
var show = function(a){ return 'welcome'}
//相當(dāng)于 省略括號
var show = a => 'welcome'
c) 參數(shù)是0個
var show = function(){ return 'welcome'}
//相當(dāng)于 省略括號
var show = () => 'welcome'
注意:箭頭函數(shù)下 ,arguments 不能使用了
var show = (a,b) => console.log(this.arguments); // 報錯
數(shù)組排序
var arr = [12,55,8];
//es5寫法
arr.sort(function(n1,n2){
return n1 - n2;
});
//es6寫法
arr.sort((n1,n2) => n1-n2);
alert(arr);
8. 面向?qū)ο?
a) 單例模式(單體模式)
let name = 'Datura';
let age = 18;
let person = {
name,
age,
sex:'Man',
showName:function(){return this.name},
showAge:function(){return this.age}
};
alert(person.showAge()); //18
alert(person.sex); //Man
b) 工廠模式
es5的面向?qū)ο蠊S模式:
首先讓我們一起來回一下es5面向?qū)ο蟮膶懛ǎ?i) 首先定義一個構(gòu)造函數(shù)(此處是 Person); ii) 定義Person的“屬性”,用this.xxx = xxx; iii) 把方法掛在原型上,Person.prototype.xxx = function(){ xxx }; iiii) 調(diào)用
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.showName = function() {
return this.name;
};
Person.prototype.showAge = function() {
return this.age;
};
var p1 = new Person('alice',18);
alert(p1.showAge()); //18
es5繼承:
//定義一個Person構(gòu)造函數(shù)
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.showName = function(){
return this.name;
};
Person.prototype.showAge = function(){
return this.age;
};
//Worker構(gòu)造函數(shù)
//繼承屬性
function Worker(name,age,job) {
//改變this指向,繼承Person的屬性
Person.apply(this,arguments);
//定義worker新的屬性
this.job = job;
}
//繼承方法
Worker.prototype = new Person();
//給worker指定“親爹”
Worker.prototype.construcotr = Worker;
//定義worker新的方法
Person.prototype.showJob = function(){
return this.job;
};
//調(diào)用
var p2 = new Worker('Datura',20,'boss');
alert(p2.showName()); //Datura
alert(p2.showJob()); //boss
es6的面向?qū)ο蠊S模式
i) 首先定義一個構(gòu)造函數(shù)(此處是 Person),注意用class關(guān)鍵字而不是function; ii) 定義Person的“屬性”,寫在constructor(){this.xxx = xxx }; iii) 定義方法,xxx () { xxx }; iiii) 調(diào)用 iiiii) 注意constructor和方法之間沒有“;”,可以給屬性初始值或默認值
class Person{
constructor(name, age=25){ //可以給屬性初始值或默認值,正常es的function函數(shù)也可以給默認值
this.name = name;
this.age = age;
}
showName(){
return this.name;
}
showAge(){
return this.age;
}
}
var p1 = new Person('alice',18);
alert(p1.showAge()); // 18
es6繼承:
//父類構(gòu)造函數(shù)Person
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
showName(){
return this.name;
}
showAge(){
return this.age;
}
}
//子類繼承父類
class Worker extends Person {
constructor(name,age,job='搬磚的'){ //繼承父類屬性,并新加屬性給默認值
super(name,age);
//這里必須傳參,也就是需要把原來構(gòu)造函數(shù)的參數(shù)傳入。
//子類必須在constructor方法中調(diào)用super方法,否則新建實例時會報錯。
//這是因為子類沒有自己的this對象,而是繼承父類的this對象,然后對其進行加工。如果不調(diào)用super方法,子類就得不到this對象。
this.job = job;
}
//給子類定義新方法showJob
showJob(){
return this.job;
}
}
//調(diào)用
var w1 = new Worker('rose',17);
alert(w1.showJob());
alert(w1.showName());
9. 模塊化
注意:目前還沒有瀏覽器支持模塊化 第三方:seajs require.js 模塊化工具 那么我們來學(xué)習(xí)下,es6自帶的模塊化
a).導(dǎo)出,將變量a“暴露”出去
const a =12;
export default a;
b).導(dǎo)入1.js文件“暴露”的東西,并用modA 接收
import modA from './1.js'; (./代表同級目錄下)
c).同一個模塊導(dǎo)出多個值 export default {a:12,b:5};
d).不同模塊間的引入
import modA from './mod1.js';
import modB from './mod2.js';
let sum = modA+modB;
export default sum;
實例:
//mod1.js文件的內(nèi)容
const a = 12;
export default a;
//mod2.js文件的內(nèi)容
const b = 5;
export default c;
//主入口(模塊)的內(nèi)容<script src="traceur.js"></script>
<script src="bootstrap.js"></script>
<script type="module">
import modA from './mod1.js';
import modB from './mod2.js';
alert(modA+modB); //17
</script>
一個子模塊“暴露”一個json數(shù)據(jù)
//mod3.js文件的內(nèi)容
export default {a:12,b:5};
//主入口(模塊)的內(nèi)容
import modA from './mod3.js';
console.log(modA.a+modA.b); // 17
1.靜態(tài)化
ES6 模塊的設(shè)計思想,是盡量的靜態(tài)化,使得編譯時就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量。
Require是CommonJS的語法,CommonJS的模塊是對象,輸入時必須查找對象屬性。
// CommonJS模塊
let { stat, exists, readFile } = require('fs');
// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
above:整體加載fs模塊(即加載fs所有方法),生成一個對象"_fs",然后再從這個對象上讀取三個方法,這叫“運行時加載”,因為只有運行時才能得到這個對象,不能在編譯時做到靜態(tài)化。
ES6模塊不是對象,而是通過export命令顯示指定輸出代碼,再通過import輸入。
import { stat, exists, readFile } from 'fs';
above:從fs加載“stat, exists, readFile” 三個方法,其他方法不加載
2.嚴格模式
ES6模塊默認使用嚴格模式,無論是否聲明“use strict”
ES6 模塊之中,頂層的**this**指向undefined
,即不應(yīng)該在頂層代碼使用this
。
Module 主要由兩個命令組成,import和export,export用于規(guī)定模塊的對外接口,import命令用于輸入其他模塊提供的功能
3.Export
模塊是獨立的文件,該文件內(nèi)部的所有的變量外部都無法獲取。如果希望獲取某個變量,必須通過export輸出,
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
或者用更好的方式:用大括號指定要輸出的一組變量
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
除了輸出變量,還可以輸出函數(shù)或者類(class),
export function multiply(x, y) {
return x * y;
};
還可以批量輸出,同樣是要包含在大括號里,也可以用as重命名:
function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
Attention:
export 命令規(guī)定的是對外接口,必須與模塊內(nèi)部變量建立一一對應(yīng)的關(guān)系
// 寫法一
export var m = 1;
// 寫法二
var m = 1;
export {m};
// 寫法三
var n = 1;
export {n as m};
// 報錯
export 1;
// 報錯
var m = 1;
export m;
報錯的寫法原因是:沒有提供對外的接口,第一種直接輸出1,第二種雖然有變量m,但還是直接輸出1,導(dǎo)致無法解構(gòu)。
同樣的,function
和class
的輸出,也必須遵守這樣的寫法。
// 報錯
function f() {}
export f;
// 正確
export function f() {};
// 正確
function f() {}
export {f};
And:export語句輸出的接口,都是和其對應(yīng)的值是動態(tài)綁定的關(guān)系,即通過該接口取到的都是模塊內(nèi)部實時的值。
位置:export模塊可以位于模塊中的任何位置,但是必須是在模塊頂層,如果在其他作用域內(nèi),會報錯。
function foo() {
export default 'bar' // SyntaxError
}
foo()
4.Import
export定義了模塊的對外接口后,其他JS文件就可以通過import來加載這個模塊,
// main.js
import {firstName, lastName, year} from './profile';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
import命令接受一對大括號,里面指定要從其他模塊導(dǎo)入的變量名,必須與被導(dǎo)入模塊(profile.js)對外接口的名稱相同。
如果想重新給導(dǎo)入的變量一個名字,可以用as關(guān)鍵字,
import { lastName as surname } from './profile';
import后的from 可以指定需要導(dǎo)入模塊的路徑名,可以是絕對路徑,也可以是相對路徑, .js路徑可以省略,如果只有模塊名,不帶有路徑,需要有配置文件指定。
注意,import
命令具有**提升效果**,會提升到整個模塊的頭部,首先執(zhí)行。(是在編譯階段執(zhí)行的)
因為import是靜態(tài)執(zhí)行的,不能使用表達式和變量,即在運行時才能拿到結(jié)果的語法結(jié)構(gòu)(e.g. if...else...)
5.module的整體加載
除了指定加載某個輸出值,還可以用(*)指定一個對象,所有的變量都會加載在這個對象上。
// circle.js。輸出兩個函數(shù)
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
// main.js 加載在個模塊
import { area, circumference } from './circle';
console.log('圓面積:' + area(4));
console.log('圓周長:' + circumference(14));
//上面寫法是逐一指定要加載的方法,整體加載的寫法如下。
import * as circle from './circle';
console.log('圓面積:' + circle.area(4));
console.log('圓周長:' + circle.circumference(14));
注意,模塊整體加載所在的那個對象(上例是circle
),應(yīng)該是可以**靜態(tài)分析的**,所以不允許運行時改變。
import * as circle from './circle';
// 下面兩行都是不允許的
circle.foo = 'hello';
circle.area = function () {};
6.export default
之前的例子中,使用import導(dǎo)入時,都需要知道模塊中所要加載的變量名或函數(shù)名,用戶可能不想閱讀源碼,只想直接使用接口,就可以用export default命令,為模塊指定輸出
// export-default.js
export default function () {
console.log('foo');
}
其他模塊加載該模塊時,import
命令可以為該匿名函數(shù)指定任意名字。
// import-default.js
import customName from './export-default';
customName(); // 'foo'
export default也可以用于非匿名函數(shù)前。
下面比較一下默認輸出和正常輸出。
// 第一組
export default function crc32() { // 輸出
// ...
}
import crc32 from 'crc32'; // 輸入
// 第二組
export function crc32() { // 輸出
// ...
};
import {crc32} from 'crc32'; // 輸入
可以看出,使用export default時,import語句不用使用大括號。
import
和export
命令只能在模塊的頂層,不能在代碼塊之中。否則會語法報錯。
這樣的設(shè)計,可以提高編譯器效率,但是沒有辦法實現(xiàn)運行時加載。
因為require是運行時加載,所以import命令沒有辦法代替require的動態(tài)加載功能。
所以引入了**import()函數(shù)**。完成動態(tài)加載。
import(specifier)
specifier用來指定所要加載的模塊的位置。import能接受什么參數(shù),import()可以接受同樣的參數(shù)。
import()返回一個Promise對象。
const main = document.querySelector('main');
import(`./section-modules/${someVariable}.js`).then(module => {
module.loadPageInto(main);
}).catch(err => {
main.textContent = err.message;
});
7.import()函數(shù)適用場合
1)按需加載:
button.addEventListener('click', event => {
import('./dialogBox.js').then(dialogBox => {
dialogBox.open();
}).catch(error => {
/* Error handling */
})
});
above: import模塊在事件監(jiān)聽函數(shù)中,只有用戶點擊了按鈕,才會加載這個模塊(很少這樣寫)。
2)條件加載:文章來源:http://www.zghlxwxcb.cn/news/detail-734225.html
import()可以放在if...else語句中,實現(xiàn)條件加載。文章來源地址http://www.zghlxwxcb.cn/news/detail-734225.html
if (condition) {
import('moduleA').then(...);
} else {
import('moduleB').then(...);
}