學習文檔地址:https://www.runoob.com/w3cnote/es6-tutorial.html
注意:本文是作者自己學習時做到記錄,不作爲es6的學習材料。槓精勿擾!
1、webpcak 打包工具
詳細資料參考webpack中文文檔 https://www.webpackjs.com/concepts/
這篇文章學習文章還可以 :https://www.jianshu.com/p/6aee48560403
範例
const path = require('path');
module.exports = {
mode: 'production',
// 入口文件配置
entry: './js/test.js',
// 輸出配置
output: {
// 出口文件
filename: 'bundle.js',
// 設置全路徑
path: path.resolve(__dirname, 'dist')
},
module: {
// 規則數組, 裏面的每一個對象都是在描述一個loader
rules: [
{
//css文件加載,正則表達式css文件的路徑
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
////圖片文件加載
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
query: {
name: 'img/[name]-[hash:5].[ext]'
}
},
],
},
]
},
devServer:{
contentBase: './dist'
}
};
常用loader:
① ES6語法轉化 babel-loader
② 打包CSS style-loader、css-loader
③ 圖片路徑處理 url-loader
④ html-withimg-loader 解決HTML文件中引入 Img標籤的問題
⑤ extract-text-webpack-plugin CSS與Js分離(一般不推薦)
⑥ 自動處理CSS3屬性前綴 postcss-loader 和 autoprefixer
⑦ 消除冗餘的CSS樣式 purifycss-webpack
⑧ 圖片壓縮 image-webpack-loader
常用插件(plugins)
① html-webpack-plugin 插件 HTML文件的發佈
② 配置JS壓縮 uglifyjs-webpack-plugin
2、gulp 自動化構建工具
詳細資料參考 gulp 中文網 https://www.gulpjs.com.cn/docs/getting-started/quick-start/
這篇文章作爲入門還可以 https://blog.csdn.net/weixin_43932245/article/details/90212725
常用的gulp插件:
- 編譯Lass (gulp-lass)
- Autoprefixer (gulp-autoprefixer)
- 縮小化(minify)CSS (gulp-minify-css)
- JSHint (gulp-jshint)
- 拼接 (gulp-concat)
- 醜化(Uglify) (gulp-uglify)
- 圖片壓縮 (gulp-imagemin)
- 即時重整(LiveReload) (gulp-livereload)
- 清理檔案 (gulp-clean)
- 圖片快取,只有更改過得圖片會進行壓縮 (gulp-cache)
- 更動通知 (gulp-notify)
// 引入 gulp
var gulp = require('gulp');
// 引入組件
var jshint = require('gulp-jshint');
var less = require('gulp-less');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var imagemin = require('gulp-imagemin'); 圖片壓縮
var cleanCSS = require('gulp-clean-css'); css壓縮
// 檢查腳本
gulp.task('lint', function() {
gulp.src('./js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'));
});
// 編譯less
gulp.task('less', function() {
gulp.src('./less/*.less')
.pipe(less())
.pipe(gulp.dest('./css'));
});
// 合併,壓縮文件
gulp.task('scripts', function() {
gulp.src('./js/*.js')
.pipe(concat('all.js'))
.pipe(gulp.dest('./dist'))
.pipe(rename('lib.min.js'))
.pipe(uglify())
.pipe(gulp.dest('./dist'));
});
// 默認任務
gulp.task('build_dev', function(){
gulp.run('lint', 'less', 'scripts');
// 監聽文件變化
gulp.watch('./js/*.js', function(){
gulp.run('lint', 'less', 'scripts');
});
});
運行gulp,執行命令爲: gulp build_dev
3、新的關鍵字 let 、 const
let
- 作用域在當前代碼塊 (var 是全局)
- 不能重複聲明
- let 不存在變量提升,var 會變量提升(let的字段需要先聲明在使用):
const
- 定義只讀變量,值不能變化(儘量值定義簡單常量,不要定義複合類型)
- 一旦聲明必須初始化,否則會報錯
for 循環計數器很適合用 let
for (var i = 0; i < 10; i++) {
setTimeout(function(){
console.log(i);
})
}
// 輸出十個 10
for (let j = 0; j < 10; j++) {
setTimeout(function(){
console.log(j);
})
}
// 輸出 0123456789
變量 i 是用 var 聲明的,在全局範圍內有效,所以全局中只有一個變量 i, 每次循環時,setTimeout 定時器裏面的 i 指的是全局變量 i ,而循環裏的十個 setTimeout 是在循環結束後才執行,所以此時的 i 都是 10。
變量 j 是用 let 聲明的,當前的 j 只在本輪循環中有效,每次循環的 j 其實都是一個新的變量,所以 setTimeout 定時器裏面的 j 其實是不同的變量,即最後輸出 12345。(若每次循環的變量 j 都是重新聲明的,如何知道前一個循環的值?這是因爲 JavaScript 引擎內部會記住前一個循環的值)。
4、解構賦值
解構賦值是對賦值運算符的擴展。他是一種針對數組或者對象進行模式匹配,然後對其中的變量進行賦值。
-
解構的源,解構賦值表達式的右邊部分。
-
解構的目標,解構賦值表達式的左邊部分。
可嵌套 、可忽略 、不完全解構 、解構默認值
let [a, [[b], c]] = [1, [[2], 3]];
// a = 1
// b = 2
// c = 3
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
// foo = 'aaa'
// bar = 'bbb'
let { baz : foo } = { baz : 'ddd' };
// foo = 'ddd'
let {a = 10, b = 5} = {a: 3};
// a = 3; b = 5;
let {a: aa = 10, b: bb = 5} = {a: 3};
// aa = 3; bb = 5;
剩餘運算符...
let [a, ...b] = [1, 2, 3];
//a = 1
//b = [2, 3]
5、數據類型 Symbol
ES6 引入了一種新的原始數據類型 Symbol ,表示獨一無二的值,最大的用法是用來定義對象的唯一屬性名。
Symbol 函數棧不能用 new 命令,因爲 Symbol 是原始數據類型,不是對象。可以接受一個字符串作爲參數,爲新創建的 Symbol 提供描述,用來顯示在控制檯或者作爲字符串的時候使用,便於區分。
let sy = Symbol("KK");
console.log(sy); // Symbol(KK)
typeof(sy); // "symbol"
// 相同參數 Symbol() 返回的值不相等
let sy1 = Symbol("kk");
sy === sy1; // false
注意點
Symbol 值作爲屬性名時,該屬性是公有屬性不是私有屬性,可以在類的外部訪問。但是不會出現在 for...in 、 for...of 的循環中,也不會被 Object.keys() 、 Object.getOwnPropertyNames() 返回。如果要讀取到一個對象的 Symbol 屬性,可以通過 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。
Symbol.for()
Symbol.for() 類似單例模式,首先會在全局搜索被登記的 Symbol 中是否有該字符串參數作爲名稱的 Symbol 值,如果有即返回該 Symbol 值,若沒有則新建並返回一個以該字符串參數爲名稱的 Symbol 值,並登記在全局環境中供搜索。
let yellow = Symbol("Yellow");
let yellow1 = Symbol.for("Yellow");
yellow === yellow1; // false
let yellow2 = Symbol.for("Yellow");
yellow1 === yellow2; // true
Symbol.keyFor()
Symbol.keyFor()
Symbol.keyFor() 返回一個已登記的 Symbol 類型值的 key ,用來檢測該字符串參數作爲名稱的 Symbol 值是否已被登記。
6、Map 對象
Maps 和 Objects 的區別:
-
一個 Object 的鍵只能是字符串或者 Symbols,但一個 Map 的鍵可以是任意值。
-
Map 中的鍵值是有序的(FIFO 原則),而添加到對象中的鍵則不是。
-
Map 的鍵值對個數可以從 size 屬性獲取,而 Object 的鍵值對個數只能手動計算。
-
Object 都有自己的原型,原型鏈上的鍵名有可能和你自己在對象上的設置的鍵名產生衝突。
forEach()
var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
// 將會顯示兩個 logs。 一個是 "0 = zero" 另一個是 "1 = one"
myMap.forEach(function(value, key) {
console.log(key + " = " + value);
}, myMap)
for...of
var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
// 將會顯示兩個 log。 一個是 "0 = zero" 另一個是 "1 = one"
for (var [key, value] of myMap) {
console.log(key + " = " + value);
}
for (var [key, value] of myMap.entries()) {
console.log(key + " = " + value);
}
/* 這個 entries 方法返回一個新的 Iterator 對象,它按插入順序包含了 Map 對象中每個元素的 [key, value] 數組。 */
// 將會顯示兩個log。 一個是 "0" 另一個是 "1"
for (var key of myMap.keys()) {
console.log(key);
}
/* 這個 keys 方法返回一個新的 Iterator 對象, 它按插入順序包含了 Map 對象中每個元素的鍵。 */
// 將會顯示兩個log。 一個是 "zero" 另一個是 "one"
for (var value of myMap.values()) {
console.log(value);
}
/* 這個 values 方法返回一個新的 Iterator 對象,它按插入順序包含了 Map 對象中每個元素的值。 */
Map 對象的操作
//Map 與 Array的轉換
var kvArray = [["key1", "value1"], ["key2", "value2"]];
// Map 構造函數可以將一個 二維 鍵值對數組轉換成一個 Map 對象
var myMap = new Map(kvArray);
// 使用 Array.from 函數可以將一個 Map 對象轉換成一個二維鍵值對數組
var outArray = Array.from(myMap);
//Map 的克隆
var myMap1 = new Map([["key1", "value1"], ["key2", "value2"]]);
var myMap2 = new Map(myMap1);
console.log(original === clone);
// 打印 false。 Map 對象構造函數生成實例,迭代出新的對象。
//Map 的合併
var first = new Map([[1, 'one'], [2, 'two'], [3, 'three'],]);
var second = new Map([[1, 'uno'], [2, 'dos']]);
// 合併兩個 Map 對象時,如果有重複的鍵值,則後面的會覆蓋前面的,對應值即 uno,dos, three
var merged = new Map([...first, ...second]);
7、set 對象
Set 對象允許你存儲任何類型的唯一值,無論是原始值或者是對象引用。
Set 對象存儲的值總是唯一的,所以需要判斷兩個值是否恆等。有幾個特殊值需要特殊對待:
-
+0 與 -0 在存儲判斷唯一性的時候是恆等的,所以不重複;
-
undefined 與 undefined 是恆等的,所以不重複;
-
NaN 與 NaN 是不恆等的,但是在 Set 中只能存一個,不重複。
// Array 轉 Set
var mySet = new Set(["value1", "value2", "value3"]);
// 用...操作符,將 Set 轉 Array
var myArray = [...mySet];
String
// String 轉 Set
var mySet = new Set('hello'); // Set(4) {"h", "e", "l", "o"}
// 注:Set 中 toString 方法是不能將 Set 轉換成 String
Set 對象作用
//數組去重
var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
//並集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var union = new Set([...a, ...b]); // {1, 2, 3, 4}
//交集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var intersect = new Set([...a].filter(x => b.has(x))); // {2, 3}
//差集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var difference = new Set([...a].filter(x => !b.has(x))); // {1}
8、Reflect 與 Proxy
Proxy 與 Reflect 是 ES6 爲了操作對象引入的 API 。
Proxy 可以對目標對象的讀取、函數調用等操作進行攔截,然後進行操作處理。它不直接操作對象,而是像代理模式,通過對象的代理對象進行操作,在進行這些操作時,可以添加一些需要的額外操作。
let target = {
name: 'Tom',
age: 24
}
let handler = {
get: function(target, key) {
console.log('getting '+key);
return target[key]; // 不是target.key
},
set: function(target, key, value) {
console.log('setting '+key);
target[key] = value;
}
}
let proxy = new Proxy(target, handler)
proxy.name // 實際執行 handler.get
proxy.age = 25 // 實際執行 handler.set
// getting name
// setting age
// 25
注意:通過構造函數新建實例時其實是對目標對象進行了淺拷貝,因此目標對象與代理對象會互相影響
target 即目標對象, handler 是一個對象,聲明瞭代理 target 的指定行爲
-
get(target, propKey, receiver)
-
set(target, propKey, value, receiver)//receiver 表示原始操作行爲所在對象,一般是 Proxy 實例本身。
-
ownKeys(target)//用於攔截對象自身屬性的讀取操作。主要包括以下操作:
-
apply(target, ctx, args)//用於攔截函數的調用、call 和 reply 操作。target 表示目標對象,ctx 表示目標對象上下文,args 表示目標對象的參數數組。
-
has(target, propKey)//用於攔截 HasProperty 操作,即在判斷 target 對象是否存在 propKey 屬性時,會被這個方法攔截。此方法不判斷一個屬性是對象自身的屬性,還是繼承的屬性。
-
construct(target, args)//用於攔截 new 命令。返回值必須爲對象。
-
deleteProperty(target, propKey)//用於攔截 delete 操作,如果這個方法拋出錯誤或者返回 false ,propKey 屬性就無法被 delete 命令刪除。
-
defineProperty(target, propKey, propDesc)//用於攔截 Object.definePro若目標對象不可擴展,增加目標對象上不存在的屬性會報錯;若屬性不可寫或不可配置,則不能改變這些屬性。
-
getOwnPropertyDescriptor(target, propKey)//用於攔截 Object.getOwnPropertyD() 返回值爲屬性描述對象或者 undefined
-
getPrototypeOf(target)//主要用於攔截獲取對象原型的操作。包括以下操作:
Reflect 可以用於獲取目標對象的行爲(內部方法),它與 Object 類似,但是更易讀,爲操作對象提供了一種更優雅的方式。它的方法與 Proxy 是對應的。
9、 字符串
-
includes():返回布爾值,判斷是否找到參數字符串。
-
startsWith():返回布爾值,判斷參數字符串是否在原字符串的頭部。
-
endsWith():返回布爾值,判斷參數字符串是否在原字符串的尾部。
-
repeat():字符串重複
-
padStart:返回新的字符串,表示用參數字符串從頭部(左側)補全原字符串。
-
padEnd:返回新的字符串,表示用參數字符串從尾部(右側)補全原字符串。
let string = "apple,banana,orange";
string.includes("banana"); // true
string.startsWith("apple"); // true
string.endsWith("apple"); // false
string.startsWith("banana",6) // true
模板字符串
模板字符串相當於加強版的字符串,用反引號 `,除了作爲普通字符串,還可以用來定義多行字符串,還可以在字符串中加入變量和表達式。模板字符串中的換行和空格都是會被保留的
let name = "Mike";
let age = 27;
let info = `My Name is ${name},I am ${age+1} years old next year.`
console.log(info);
// My Name is Mike,I am 28 years old next year.
//當模板字符串中帶有變量,會將模板字符串參數處理成多個參數。
function f(stringArr,...values){
let result = "";
for(let i=0;i<stringArr.length;i++){
result += stringArr[i];
if(values[i]){
result += values[i];
}
}
return result;
}
let name = 'Mike';
let age = 27;
f`My Name is ${name},I am ${age+1} years old next year.`;
// "My Name is Mike,I am 28 years old next year."
f`My Name is ${name},I am ${age+1} years old next year.`;
// 等價於
f(['My Name is',',I am ',' years old next year.'],'Mike',28);
注意:模板字符串中的換行和空格都是會被保留的
國際化處理(轉化多國語言)
i18n`Hello ${name}, you are visitor number ${visitorNumber}.`;
10、數字
二進制表示法新寫法: 前綴 0b 或 0B 。
常量
-
最小誤差值: Number.EPSILON
-
最大安全整數 Number.MAX_SAFE_INTEGER
-
最小安全整數 Number.MIN_SAFE_INTEGE
方法
-
Number.isFinite() //一個數值是否爲有限的
-
Number.parseInt()//轉換爲整數 ,
無法被解析成浮點數,則返回 NaN -
Number.isSafeInteger //用於判斷數值是否在安全範圍內。
-
Number.isInteger //用於判斷給定的參數是否爲整數。
整數和浮點數採用的是同樣的儲存方法,因此 1 與 1.0 被視爲相同的值
數字處理
-
Math.trunc:用於返回數字的整數部分。
-
Math.fround:用於獲取數字的32位單精度浮點數形式。
-
Math.sign:判斷數字的符號(正、負、0)
11、ES6 對象
屬性的簡潔表示法 ,ES6允許對象的屬性直接寫變量,這時候屬性名是變量名,屬性值是變量值。
const age = 12;
const name = "Amy";
const person = {age, name};
person //{age: 12, name: "Amy"}
//等同於
const person = {age: age, name: name}
方法名也可以簡寫,如果是Generator 函數,則要在前面加一個星號:
ES6允許用表達式作爲屬性名,但是一定要將表達式放在方括號內。
const obj = {
["he"+"llo"](){
return "Hi";
}
}
obj.hello(); //"Hi"
注意點:屬性的簡潔表示法和屬性名錶達式不能同時使用,否則會報錯。
拓展運算符(...)
用於取出參數對象所有可遍歷屬性然後拷貝到當前對象。
可用於合併兩個對象
let age = {age: 15};
let name = {name: "Amy"};
let person = {...age, ...name};
person; //{age: 15, name: "Amy"}
對象的新方法
- Object.assign(target, source_1, ···)用於將源對象的所有可枚舉屬性複製到目標對象中。
assign 的屬性拷貝是淺拷貝,同名屬性後面的替換前面的
- Object.is(value1, value2)用來比較兩個值是否嚴格相等,與(===)基本類似。
基本用法
Object.is("q","q"); // true
Object.is(1,1); // true
Object.is([1],[1]); // false
Object.is({q:1},{q:1}); // false
與(===)的區別
//一是+0不等於-0
Object.is(+0,-0); //false
+0 === -0 //true
//二是NaN等於本身
Object.is(NaN,NaN); //true
NaN === NaN //false
12、數組
-
Array.of()將參數中所有值作爲元素形成數組。
-
Array.from(arrayLike[, mapFn[, thisArg]])
將類數組對象或可迭代對象轉化爲數組。
arrayLike 想要轉換的類數組對象或可迭代對象。
mapFn 可選,map 函數,用於對每個元素進行處理,放入數組的是處理後的元素。
thisArg 可選,用於指定 map 函數執行時的 this 對象。
let map = {
do: function(n) {
return n * 2;
}
}
let arrayLike = [1, 2, 3];
console.log(Array.from(arrayLike, function (n){
return this.do(n);
}, map)); // [2, 4, 6]
類數組對象
一個類數組對象必須含有 length 屬性,且元素屬性名必須是數值或者可轉換爲數值的字符。
擴展方法
find()查找數組中符合條件的元素,若有多個符合條件的元素,則返回第一個元素。
findIndex()查找數組中符合條件的元素索引,若有多個符合條件的元素,則返回第一個元素索引。
let arr = Array.of(1, 2, 1, 3);
// 參數1:回調函數
// 參數2(可選):指定回調函數中的 this 值
console.log(arr.findIndex(item => item = 1)); // 0
// 數組空位處理爲 undefined
console.log([, 1].findIndex(n => true)); //0
fill() 將一定範圍索引的數組元素內容填充爲單個指定的值。
let arr = Array.of(1, 2, 3, 4);
// 參數1:用來填充的值
// 參數2:被填充的起始索引
// 參數3(可選):被填充的結束索引,默認爲數組末尾
console.log(arr.fill(0,1,2)); // [1, 0, 3, 4]
copyWithin() 將一定範圍索引的數組元素修改爲此數組另一指定範圍索引的元素。
// 參數1:被修改的起始索引
// 參數2:被用來覆蓋的數據的起始索引
// 參數3(可選):被用來覆蓋的數據的結束索引,默認爲數組末尾
console.log([1, 2, 3, 4].copyWithin(0,2,4)); // [3, 4, 3, 4]
// 參數1爲負數表示倒數
console.log([1, 2, 3, 4].copyWithin(-2, 0)); // [1, 2, 1, 2]
console.log([1, 2, ,4].copyWithin(0, 2, 4)); // [, 4, , 4]
includes()數組是否包含指定值。
flat()嵌套數組轉一維數組
flatMap() 先對數組中每個元素進行了的處理,再對數組執行 flat() 方法。
// 參數1:遍歷函數,該遍歷函數可接受3個參數:當前元素、當前元素索引、原數組
// 參數2:指定遍歷函數中 this 的指向
console.log([1, 2, 3].flatMap(n => [n * 2])); // [2, 4, 6]
複製數組
let arr = [1, 2],
arr1 = [...arr];
console.log(arr1); // [1, 2]
// 數組含空位
let arr2 = [1, , 3],
arr3 = [...arr2];
console.log(arr3); [1, undefined, 3]
合併數組
console.log([...[1, 2],...[3, 4]]); // [1, 2, 3, 4]
13、函數
默認參數
function fn(name,age=17){
console.log(name+","+age);
}
fn("Amy",18); // Amy,18
fn("Amy",""); // Amy,
fn("Amy"); // Amy,17
只有在未傳遞參數,或者參數爲 undefined 時,纔會使用默認參數,null 值被認爲是有效的值傳遞。
注意點:使用函數默認參數時,不允許有同名參數。
不定參數
不定參數用來表示不確定參數個數,形如,...變量名,由...加上一個具名參數標識符組成。具名參數只能放在參數組的最後,並且有且只有一個不定參數。
箭頭函數
箭頭函數體中的 this 對象,是定義函數時的對象,而不是使用函數時的對象。
//適合使用的場景
// 回調函數
var Person = {
'age': 18,
'sayHello': function () {
setTimeout(function () {
console.log(this.age);
});
}
};
var age = 20;
Person.sayHello(); // 20
var Person1 = {
'age': 18,
'sayHello': function () {
setTimeout(()=>{
console.log(this.age);
});
}
};
var age = 20;
Person1.sayHello(); // 18
//不適合使用的場景
//定義函數的方法,且該方法中包含 this
var Person = {
'age': 18,
'sayHello': ()=>{
console.log(this.age);
}
};
var age = 20;
Person.sayHello(); // 20
// 此時 this 指向的是全局對象
var Person1 = {
'age': 18,
'sayHello': function () {
console.log(this.age);
}
};
var age = 20;
Person1.sayHello(); // 18
// 此時的 this 指向 Person1 對象
14、迭代器
Iterator 是 ES6 引入的一種新的遍歷機制,迭代器有兩個核心概念:
-
迭代器是一個統一的接口,它的作用是使各種數據結構可被便捷的訪問,它是通過一個鍵爲Symbol.iterator 的方法來實現。
-
迭代器是用於遍歷數據結構元素的指針(如數據庫中的遊標)。
可迭代的值:
- Array
- String
- Map
- Set
普通對象不可迭代
of 操作數必須是可迭代,這意味着如果是普通對象則無法進行迭代。如果數據結構類似於數組的形式,則可以藉助 Array.from() 方法進行轉換迭代
const arrayLink = {length: 2, 0: "zero", 1: "one"}
// 報 TypeError 異常
for (let item of arrayLink) {
console.log(item);
}
// 正常運行
// output:
// zero
// one
for (let item of Array.from(arrayLink)) {
console.log(item);
}
15、Class 類
class (類)作爲對象的模板被引入,可以通過 class 關鍵字定義類。
class 的本質是 function。
它可以看作一個語法糖,讓對象原型的寫法更加清晰、更像面向對象編程的語法。
// 匿名類
let Example = class {
constructor(a) {
this.a = a;
}
}
// 命名類
let Example = class Example {
constructor(a) {
this.a = a;
}
}
類定義不會被提升,這意味着,必須在訪問前對類進行定義,否則就會報錯。
類中方法不需要 function 關鍵字。
方法間不能加分號。
-
name:屬性返回跟在 class 後的類名(存在時)。
-
constructor:方法 類的默認方法,創建類的實例化對象時被調用。
-
new :class 的實例化必須通過 new 關鍵字。
-
extends:通過 extends 實現類的繼承。
16、export 與 import
導出(export) @與導入(import)兩個模塊。
模塊導入導出各種類型的變量,如字符串,數值,函數,類。
-
導出的函數聲明與類聲明必須要有名稱(export default 命令另外考慮)。
-
不僅能導出聲明還能導出引用(例如函數)。
-
export 命令可以出現在模塊的任何位置,但必需處於模塊頂層。
-
import 命令會提升到整個模塊的頭部,首先執行。
/*-----export [test.js]-----*/
let myName = "Tom";
let myAge = 20;
let myfn = function(){
return "My name is" + myName + "! I'm '" + myAge + "years old."
}
let myClass = class myClass {
static a = "yeah!";
}
export { myName, myAge, myfn, myClass }
/*-----import [xxx.js]-----*/
import { myName, myAge, myfn, myClass } from "./test.js";
console.log(myfn());// My name is Tom! I'm 20 years old.
console.log(myAge);// 20
console.log(myName);// Tom
console.log(myClass.a );// yeah!
//建議使用大括號指定所要輸出的一組變量寫在文檔尾部,明確導出的接口。
//函數與類都需要有對應的名稱,導出文檔尾部也避免了無對應名稱。
import 命令的特點
-
只讀屬性:不允許在加載模塊的腳本里面,改寫接口的引用指向,即可以改寫 import 變量類型爲對象的屬性值,不能改寫 import 變量類型爲基本類型的值。
-
單例模式:多次重複執行同一句 import 語句,那麼只會執行一次,而不會執行多次。import 同一模塊,聲明不同接口引用,會聲明對應變量,但只執行一次 import 。
-
靜態執行特性:import 是靜態執行,所以不能使用表達式和變量。
export default 命令
-
在一個文件或模塊中,export、import 可以有多個,export default 僅有一個。
-
export default 中的 default 是對應的導出接口變量。
-
通過 export 方式導出,在導入時要加{ },export default 則不需要。
-
export default 向外暴露的成員,可以使用任意變量來接收。
17、Promise 對象
Promise 異步操作有三種狀態:pending(進行中)、fulfilled(已成功)和 rejected(已失敗)。除了異步操作的結果,任何其他操作都無法改變這個狀態。
Promise 對象只有:從 pending 變爲 fulfilled 和從 pending 變爲 rejected 的狀態改變。只要處於 fulfilled 和 rejected ,狀態就不會再變了即 resolved(已定型)。
const p1 = new Promise(function(resolve,reject){
resolve('success1');
resolve('success2');
});
const p2 = new Promise(function(resolve,reject){
resolve('success3');
reject('reject');
});
p1.then(function(value){
console.log(value); // success1
});
p2.then(function(value){
console.log(value); // success3
});
狀態的缺點:
無法取消 Promise ,一旦新建它就會立即執行,無法中途取消。
如果不設置回調函數,Promise 內部拋出的錯誤,不會反應到外部。
當處於 pending 狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。
then 方法
then 方法接收兩個函數作爲參數,第一個參數是 Promise 執行成功時的回調,第二個參數是 Promise 執行失敗時的回調,兩個函數只會有一個被調用。
在 JavaScript 事件隊列的當前運行完成之前,回調函數永遠不會被調用。
const p = new Promise(function(resolve,reject){
resolve('success');
});
p.then(function(value){
console.log(value);
});
console.log('first');
// first
// success
注意點
簡便的 Promise 鏈式編程最好保持扁平化,不要嵌套 Promise。
注意總是返回或終止 Promise 鏈。
18、Generator 函數
ES6 新引入了 Generator 函數,可以通過 yield 關鍵字,把函數的執行流掛起,爲改變執行流程提供了可能,從而爲異步編程提供解決方案。Generator 有兩個區分於普通函數的部分:
-
一是在 function 後面,函數名之前有個 * ;
-
函數內部有 yield 表達式。
其中 * 用來表示函數爲 Generator 函數,yield 用來定義函數內部的狀態。
function* func(){
console.log("one");
yield '1';
console.log("two");
yield '2';
console.log("three");
return '3';
}
執行機制
調用 Generator 函數和調用普通函數一樣,在函數名後面加上()即可,但是 Generator 函數不會像普通函數一樣立即執行,而是返回一個指向內部狀態對象的指針,所以要調用遍歷器對象Iterator 的 next 方法,指針就會從函數頭部或者上一次停下來的地方開始執行
f.next();
// one
// {value: "1", done: false}
f.next();
// two
// {value: "2", done: false}
f.next();
// three
// {value: "3", done: true}
f.next();
// {value: undefined, done: true}
19、async 函數
ES7 纔有的與異步操作有關的關鍵字,和 Promise , Generator 有很大關聯的。
async function name([param[, param[, ... param]]]) { statements }
-
name: 函數名稱。
-
param: 要傳遞給函數的參數的名稱。
-
statements: 函數體語句。
sync 函數中可能會有 await 表達式,async 函數執行時,如果遇到 await 就會先暫停執行 ,等到觸發的異步操作完成後,恢復 async 函數的執行並返回解析值。
await 關鍵字僅在 async function 中有效 ,await 操作符用於等待一個 Promise 對象, 它只能在異步函數 async function 內部使用。
function testAwait (x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function helloAsync() {
var x = await testAwait ("hello world");
console.log(x);
}
helloAsync ();
// hello world
返回值
返回 Promise 對象的處理結果。如果等待的不是 Promise 對象,則返回該值本身。
如果一個 Promise 被傳遞給一個 await 操作符,await 將等待 Promise 正常處理完成並返回其處理結果。
function testAwait (x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function helloAsync() {
var x = await testAwait ("hello world");
console.log(x);
}
helloAsync ();
// hello world
await針對所跟不同表達式的處理方式:
- Promise 對象:await 會暫停執行,等待 Promise 對象 resolve,然後恢復 async 函數的執行並返回解析值。
- 非 Promise 對象:直接返回對應的值。