makeIterator是個遍歷器,生成遍歷器對象itnode
var it = makeIterator(['a', 'b']); it.next() // { value: "a", done: false } it.next() // { value: "b", done: false } 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}; } }; }
對象具備Symbol.iterator
方法就是部署了iterable接口,但若是Symbol.iterator
返回的不是遍歷對象,會報錯。下面對象部署了iterable接口git
var obj = { value : 1, [Symbol.iterator](){ let me = this return { next(){ return { value: me.value++, done: me.value >= 10 } } } } }
iterable接口爲數據結構提供統一的數據訪問機制,具備線性訪問特色。es6
原生部署的有:數組、相似數組對象、Set和Map,數組、Set、Map的entries、keys、values方法的返回。
相似數組對象如 arguments對象 DOM NodeList對象;github
對象部署Iterator接口:ajax
function* entries(obj){ for(let key of Object.keys(obj)){ yield [key, obj[key]] } }
解構賦值、擴展運算符、yield *、for…of、Array.from、Map()、Set() Promise.all Promise.tracechrome
for…of
對比for…in
for…in編程
獲取鍵名,無序的,循環對象全部可枚舉的屬性,做用數組時,返回的key是字符串json
for…of數組
of後面跟遍歷器對象,或者部署了遍歷器接口的數據類型。返回有序元素,相對與forEach能夠break、continuepromise
若是跟makeIterator,會報錯
for(let v of [1,2,3]){console.log(v)} for(let v of [1,2,3][Symbol.iterator]()){console.log(v)}//兩結果同樣
通常用在for...of循環中提早退出break時或者throw,會執行定義在遍歷器中return方法,return方法必須返回一個對象
'use strict'; /** * node v6.9.0 chrome52下執行return * @type {{cur: number}} */ var obj = { cur: 1, next() { return { value: this.cur++, done: false } }, return() { this.cur = 0 console.log('execute iterator\'s method of return') return { done: true } }, [Symbol.iterator]() { // 沒有會報錯 return this; } }; for (let v of obj[Symbol.iterator]()) { //throw new Error(); 也會執行return if (v > 10) { break; } if (v == 8) { continue; } console.log(v); }
g.return(data) 返回{value:data,done:true},nodeJs6.2.2支持。
/** * return nodeJs暫不支持,調用會報錯,nodeJs6.2.2支持 */ function* gen(){ yield 1; try{ yield 11; yield 22; yield 33; }finally{ console.log('a') yield 21; yield 22; } yield 2; } let itr = gen() console.log(itr.next()) // { value: 1, done: false } console.log(itr.return(31)) // { value: 31, done: true } console.log(itr.next()) // { value: undefined, done: true } console.log(itr.next()) // { value: undefined, done: true } console.log(itr.next()) // { value: undefined, done: true }
g.throw()
遍歷器對象能夠執行throw,generator函數內部有try...catch
,再被catch,直到運行結束或者執行時遇到下一個next。若是沒被捕獲,好比連續throw兩次,會拋到generator外面。
/** * 一開始沒執行next,就執行throw,內部沒法捕獲。 */ function* gen(){ try{ console.log('start') yield 1; }catch(e){ console.log('內部捕獲',e) } yield 2; } var g = gen(); try{ //g.throw('a'); console.log(g.next()) console.log(g.throw('b')) }catch(e){ console.log('外部捕獲',e) } /** * 遍歷器對象連續兩次throw */ function* errCnt() { try { yield 5 // { value: 5, done: false } } catch (e) { console.log('內部捕獲', e) //throw new Error('cry') } yield 6 yield 7 } var itr = errCnt() console.log(itr.next()) console.log(itr.throw('a')) // { value: 6, done: false } try { console.log(itr.throw('a')) } catch (e) { console.log('外部捕獲', e) console.log(itr.next()) // { value: undefined, done: true } }
Generator函數體內報錯,外部捕獲後,下次還執行next,done爲true,value undefined
'use strict'; function* foo() { let x = yield 3; let y = x.toUpperCase(); yield y; yield 5; } var it = foo(); console.log(it.next()); // { value:3, done:false } try { console.log(it.next(42)); } catch (err) { console.log(err); console.log(it.next()); // {value: undefined, done: true} }
Generator的遍歷器對象拋錯後,內部沒捕獲,外部捕獲,下次執行next,同上
AA必須是部署了遍歷器接口的數據結構,A若是是Generator生成的,且Generator有return,會將值賦值到a。
function* gen1(){ yield 1; yield 2; return 3; } function* gen2(gen){ yield 11; let rtn = yield* gen(); console.log('rtn: ' + rtn) yield 22; } let itr1 = gen1() console.log(itr1.next()) // { value: 1, done: false } console.log(itr1.next()) // { value: 2, done: false } console.log(itr1.next()) // { value: 3, done: true } let itr2 = gen2(gen1) console.log(itr2.next()) // { value: 11, done: false } console.log(itr2.next()) // { value: 1, done: false } console.log(itr2.next()) // { value: 2, done: false } // rtn: 3 console.log(itr2.next()) // { value: 22, done: false } console.log(itr2.next()) // { value: undefined, done: true } for(let v of gen2(gen1)){ console.log(v) }
AA若是直接是Generator,會報錯;for...of若是直接是Generator,也會報錯。
function* gen(){ yield 1; yield 2; yield this.name = ’sprying' } gen.prototype.sayHi = () =>console.log(‘hi') const g = gen() g.next() g.next() g.next() g.sayHi() g.name // null
若是上面const g = gen()換成
const g = gen.apply(gen.prototype)
這時候g.name就有值
注意new gen會報錯
Generator函數的原型時Generator.prototype(假設是ownProto);
ownProto原型是sharedProto,sharedProto.hasOwnProperty("next")
sharedProto的原型是iterProto,iterProto.hasOwnProperty(Symbol.iterator)
函數遇到異步操做時,yield暫停,異步回調觸發時,再繼續執行。具體實現流程以下:
promise
yield返回結果是promise對象,異步響應時,觸發then,即
// 業務代碼 function * gen(){ yield new Promise((resolve, reject) => { setTimeout(()=>{ resolve({ok: true}) }, 500) }) } // 執行器背後的核心處理邏輯,執行next後,value是promise promise.then(function(data){ g.next(data) })
thunkify
yield返回參數是函數,傳入回調,執行這個函數。異步響應時,執行回調,回調的參數是data,即。
// 業務代碼 function * gen(){ yield function(callback){ setTimeout(()=>{ callback({ok: true}) }, 500) } } // 執行器背後的核心處理邏輯 hook((data) = >{ g.next(data) })
假設下面場景
fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); }); yield function(callback){ fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; callback(data) }); }
每次都這樣寫,是否是很麻煩?咱們能夠封裝個函數
function thunkify(callback){ return function(...args){ return function(hook){ callback(...[...args, hook]) } } } // 下面就簡潔了不少 const readFile = thunkify(fs.readFile) function * gen(){ yield readFile(filename) }
function* gen(){ yield 1; yield 2; yield 3; return 4; } for(let v of gen()){ console.log(v) }//1,2,3
resolve能夠傳入下一個promise實例
/** * 注意執行順序 */ setTimeout(()=>console.log(1),0) new Promise(function (resolve, reject) { console.log(2); x/2; resolve(); }).then(function () { console.log(3) //throw new Error('err') },function(err){ console.log(err) }); console.log(4)
錯誤沒被捕獲,觸發下面
process.on('unhandledRejection', function (err, p) {}) /** * reject未被catch,會被傳遞到unhandledRejection * Promise內部throw沒被catch,會被傳遞到unhandledRejection,其它不作任何處理 * throw後有catch,還有then,可是then應該是catch生成的默認resolve的promise */ new Promise((resolve, reject) => { //reject(new Error('err')) //setTimeout(() => { throw new Error('err-1') //}, 0) //resolve('done') }) .catch(err => console.log('err: ', err)) .then((data) => { console.log('then: ' + data) }) process.on('unhandledRejection', function (err, p) { //console.error(err.stack) }); var someAsyncThing = function () { return new Promise(function (resolve, reject) { // 下面一行會報錯,由於x沒有聲明 resolve(x + 2); }); }; // 注意執行時間 ///* someAsyncThing() .catch(function (error) { console.log('oh no', error); }) .then(function () { console.log('carry on'); }); //*/
參數是具備Iterator接口的對象,若是都是fulfilled,觸發的then的參數回調的參數是數組。若是首先一個出來rejected,錯誤捕獲的回調參數是首先出現錯誤那個。Promise.all對應的各個值若是不是Promise,調用Promise.resolve
誰先改變狀態,結果和回調的參數就聽誰
var jsPromise = Promise.resolve($.ajax('/whatever.json'));
參數是個thenable對象,當即執行thenable對象的then
參數是其它值,好比字符串
參數是空的
/** * Created by yingchun.fyc@alibaba-inc.com on 16/7/13. */ let thenable = { then(resolve, reject){ resolve('thenable') } } Promise.resolve(thenable).then(res => console.log(res)) var p = Promise.resolve('hi') p.then(res => console.log(res)) // 輸出 // hi // thenable
參數同上
generator函數容許執行暫停。當遇到yield時暫停,Js代碼能夠控制繼續執行,好比控制yield後面的異步響應後,繼續執行。暫停、和繼續執行是咱們寫的Js代碼控制,也就是,實現個執行器,讓這些操做自動執行,就能夠實現同步方式寫異步代碼。
執行器是個函數,返回promise。約定yield後面跟promise或者thunk函數。執行器執行到g.next(),返回obj,obj.value裏的異步響應後,若是obj.done爲false,繼續執行,將響應的值傳給g.next(data),如此循環。若是何時g.next,返回的done是true,那麼等待value異步響應後,resolve響應的值,結束循環。
若是g.next時,報錯,首先g.throw給generator處理,處理完繼續next;處理失敗,直接結束。若是異步響應出錯,一樣處理。thunk函數,異步響應時執行callback,規定第一參數傳錯誤信息。
要並行處理異步時,yield後面跟數組、對象,執行器Promise.all下處理。
若是Generator函數,再套了一個Generator,放在yield後面。執行器裏就再調一次執行器。
上面就是co的實現原理。
如今咱們反思這樣一個問題,同步方式寫異步代碼,遇到異步時,程序等待異步響應後,再繼續執行,那麼nodeJs異步處理優點就沒了嗎?一開始,我也是這麼認爲的,可是co執行Generator函數時,雖然內部yield暫停了,可是整個Generator並無所以卡住,仍是會繼續執行co後續邏輯。因此nodeJs異步處理的優點還在。
async屬於ES7,不過引入babel的transform-async-to-generator就能夠轉碼使用。await在ES6是保留字,ES5中使用它是合法。
普通函數中使用await會報錯。
Async函數有多種使用形式。
// 函數聲明 async function foo() {} // 函數表達式 const foo = async function () {}; // 對象的方法 let obj = { async foo() {} }; // 箭頭函數 const foo = async () => {};
async、await組合跟執行器co很像,只是它再也不須要執行器了,像通常函數調用,返回的仍然是Promise。await相比co的yield,後面能夠是基本數據類型。
至於錯誤處理機制,實際上跟co結果同樣。不想結束,也是須要try...catch。或者promise後加catch。
至於併發執行,先都生成Promise實例,而後await。或者Promise.all([asyncMethod1(), asyncMethod2()])
/** * Created by yingchun.fyc@alibaba-inc.com on 16/9/12. */ async function f() { try { await Promise.reject('出錯了'); } catch(e) { } return await Promise.resolve('hello world'); } f() .then(v => console.log(v)) async function dbFuc(fn) { let docs = [1,2,3]; let promises = docs.map((doc) => fn(doc)); let results = await Promise.all(promises); console.log(results); } // 或者使用下面的寫法 // 兩個運行實際差很少,由於都是先生成了promise,再調用await。await、yield,參數默認值都是延遲執行的。 async function dbFuc1(fn) { let docs = [4,5,6]; let promises = docs.map((doc) => fn(doc)); let results = []; for (let promise of promises) { results.push(await promise); } console.log(results); } var startTime = (new Date()).getTime() dbFuc1((data) => { return new Promise((resolve, reject) => { setTimeout(()=>{ resolve(data) }, 1000) }) }).then(() =>{ console.log((new Date().getTime() - startTime)) })
關鍵字class定義類,方法之間沒有,
,方法名能夠是變量[defineVar],定義的class只能new,不然報錯。方法名不可枚舉。構造函數在constructor方法中定義
可使用Object.assign新增方法。
class 不存在變量提高
class表達式
let myClass = class Me {} //Me.name只能內部調用,Me也只能內部用 myClass.name // Me
實例的__proto__,指向原型對象
私有方法
使用Symbol定義方法名
const bar = Symbol(「bar")
繼承重寫constructor,要在constructor中先調用super(),不然會報錯。
super在對象方法中均可以使用,可是奇怪的是,下面第一個正常,第二個會報錯。
var obj = { toString() { return "MyObject: " + super.toString(); } }; var obj = { toString: function() { return "MyObject: " + super.toString(); } };
能夠繼承原生的構造函數,可是繼承Object時,沒法向父類的構造函數傳入參數。
相比es5的繼承不能繼承原生的構造函數,即便es5繼承了,也不具有原生的能力。
Object.getPrototypeOf獲取類的父類
Object.getPrototypeOf(B) === A Object.setPrototypeOf Object.setPrototypeOf = function (obj, proto) { obj.__proto__ = proto; return obj; }
方法名前可加set/get,而且是定義在descriptor上,Object.getOwnPropertyDescriptor
方法名前可加static
es7才支持屬性名直接在類裏定義
關於class具體使用例子,這裏就不貼出來了。
支持嵌套,等號右邊是可遍歷(iterator)的結構
等號兩邊能夠不徹底匹配,或左邊小,或右邊沒相應值(這時undefined)
支持默認值,默認值若是是表達式,表達式是惰性求值的
let [x=y,y=1] = [1,2] let [a=b,b=1] = []// Uncaught ReferenceError: b is not defined(…) var [a, , [b], c] = [5, null, [6]]; var [a, , [b], c] = [5, undefined, [6]]; var [a, , [b], c] = [5, , [6]];// a = 5; b = 6; c = undefined var [a, b, c] = "ab"; // a = 'a'; b = 'b'; c = undefined var [c] = "𠮷嗰"; // c = "𠮷" var [a,] = [1]; // a = 1
變量名和屬性名不一致,是經過模式對應起來
var { foo: baz } = { foo: 'aaa', bar: 'bbb' }; baz // "aaa" foo // Uncaught ReferenceError: foo is not defined(…)
聲明語句、賦值語句
let foo; let {foo} = {foo: 1};// Uncaught SyntaxError: Identifier 'foo' has already been declared ({foo} = {foo: 1})// 不報錯
嵌套
var node = { loc: { start: { line: 1, column: 5 } } }; var { loc: { start: { line }} } = node; line // 1 loc // Uncaught ReferenceError: loc is not defined(…) start // error: start is undefined let obj = {}; let arr = []; ({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true }); obj // {prop:123} arr // [true]
默認值
var {x:y =3} = {x:5} // y 5
賦值時嚴格的等於undefined
解構失敗
var {foo} = {bar: 'baz'}; foo // undefined
其它
var {foo: {bar}} = {baz: 'baz'}; Uncaught TypeError: Cannot match against 'undefined' or 'null'.(…) var qux = "corge"; var { [qux]: grault } = { corge: "garply" } // grault = "garply"
解構賦值容許,等號左邊的模式之中,不存在任何變量名
({} = [true, false]);
能夠將對象的方法,解構賦值給變量
let { log, sin, cos } = Math;
字符串、數值、布爾值的解構賦值
let {length : len} = 'hello'; let {toString: s} = 123; s === Number.prototype.toString // true
解構賦值的規則是,只要右邊的值不是對象,先轉爲對象。因爲undefined和null沒法轉爲對象,因此解構賦值時,會報錯
函數參數的解構賦值
function move({x = 0, y = 0} = {}) { return [x, y]; }
函數參數的默認值
[1, undefined, 3].map((x = 'yes') => x);
可使用()場景
賦值語句,非模式部分
[(b)] = [3]; // 正確 ({ p: (d) } = {}); // 正確 [(parseInt.prop)] = [3]; // 正確 var a, b; ({a,b} = {a:1,b:2}); try { eval("({a,b}) = {a:3,b:4};");//報錯 } catch(e) { return a === 1 && b === 2; } var [a,b] = [5,6], {c,d} = {c:7,d:8};
var [c, ...d] = [6]; // c = 6; d.length=0
[x, y] = [y, x];
函數返回多個值
var [a, b, c] = example();
函數參數的默認值
jQuery.ajax = function (url, { async = true, beforeSend = function () {}, cache = true, complete = function () {}, crossDomain = false, global = true, // ... more config }) { // ... do stuff };
遍歷Map結構
var map = new Map(); map.set('first', 'hello'); map.set('second', 'world'); for (let [key, value] of map) { console.log(key + " is " + value); }
輸入模塊的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map");
函數參數若是是對象的解構賦值,執行的時候對象的解構賦值要有值,不論是函數參數默認值或者是傳入的值
函數參數的默認值是個表達式,表達式會延遲執行
函數參數默認值的做用域,是函數的做用域
var x = 1; function foo(x, y = function() { x = 2; }) { var x = 3; y(); console.log(x); } foo() // 3
感受比較奇怪,按理來講,y執行時的做用域,就是定義時的做用域,參數中的做用域都是函數範圍內做用域。因此參數中x就應該與下面一致。實際上最後輸出的x爲3
把var換成let,在chrome 52下就報錯了
函數的參數默認值位置
建議位於後面幾個參數,若是有默認值的參數,後面還有要輸入的參數,執行的時候,foo(undefined, 1)
函數的length
除去有默認值參數,以及後面的全部參數
function testfn1(a = 1, x, h, y =2){} testfn1.length // 0
function throwIfMissing(){ throw new Error('Missing parameter') } function foo(mustBeProvided = throwIfMissing()){ return mustBeProvided } foo()
對應的變量是個數組,後面不能再跟其它參數,function的length是除了rest參數的函數長度;
arguments.length仍是按之前方式
(function (foo, ...args) { foo = "qux"; // The arguments object is not mapped to the // parameters, even outside of strict mode. return arguments.length === 3 && arguments[0] === "foo" && arguments[1] === "bar" && arguments[2] === "baz"; }("foo", "bar", "baz"))
後跟部署iterale接口的數據結構,將數據結構變成逗號相隔的參數序列
console.log(1, ...[2, 3, 4], 5) function add(x, y) { return x + y; } var numbers = [4, 38]; add(...numbers) // 42 let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; [...arrayLike] Uncaught TypeError: arrayLike[Symbol.iterator] is not a function(…) Array.from(arrayLike) ["a", "b", "c"]
函數表達式定義方式中,相比es5,es6中函數的name是被賦值的名字。
bind的函數,返回bound開頭
let fn1 = function(){} let fn2 = fn1 n2.name //fn1 (new Function).name //anonymous fn1.bind({}).name //bound fn1 (function(){}).name // (function(){}).bind({}).name //"bound "
let arrowFn1 = ({x,y}) => [x,y] let arrowFn2 = (...arr) => [...arr]
不具備this,不能當作構造函數,沒有本身的arguments。
this指向定義時所處的this,使用bind無效
es7內容,前面是綁定的對象,後面是函數,babel轉碼器已經支持
直接量寫法中,容許屬性值省略,方法簡寫,容許屬性名或方法名使用[]包圍的表達式,但這時不能省略屬性值。
let obj = { * m(){ yield 'hello world' } } module.export = {add, remove}
對象方法也有name,同函數name狀況,可是這裏,若是是Symbol,返回的是Symbol描述。若是是set、get方法,返回加上前綴set get
Object.assign 第一個參數是目標對象,沒法轉爲對象(undefined\null)時會報錯,源對象是任意,當是數字、布爾值、undefined\null時,忽略。
Object.assign 拷貝自身可枚舉的對象屬性、Symbol屬性,淺拷貝
Object.assign 一個參數時,返回自身
Object.assign(true) // Boolean {[[PrimitiveValue]]: true} Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3]
克隆對象
Object.assign({}, origin)
克隆繼承屬性
function clone(origin){ originObj = Object.getPrototypeOf(origin) return Object.assign(Object.create(originObj), origin) }
JSON.stringify() 串行化對象自身可枚舉屬性
getOwnPropertyDescriptor
Object.getOwnPropertyDescriptor([], 'length').enumerable // false 我覺得要在原型上取到length,由於Object.getOwnPropertyDescriptor({},"toString」)// null
for…of
包括繼承的全部可枚舉的屬性,不包含SymbolObject.keys
全部自身可枚舉的屬性,不包含SymbolObejct.getOwnPropertyNames
自身全部屬性,包括不可枚舉,不包含SymbolObject.getOwnPropertySymbols(obj)
Reflect.ownKeys
返回全部自身屬性的數組,不論是不是可枚舉、Symbol遍歷次序
按數字排序;字符串屬性,按生成時間排序;Symbol屬性,按生成時間排序
Same-value equality,相對於===,但NaN等於自身,+0不等-0
本身實現以下
Object.defineProperty(Object, ‘is’, { value: function(x, y){ if(x === y){ return x ===0 || 1/x === 1/y } return x !==x && y !==y }, configurable: true, enumerable: false, writable: true })
__proto__
es6附錄中,只規定瀏覽器端支持,爲了保險,仍是用
Object.setPrototypeOf`` Object.getPrototypeOf
Object.create
Object.getPrototypeOf({__proto__: null})// null
Object.values
es7 提案,取值規則、順序同keys,
Object.values(2)//[] Object.values(true)//[] Object.keys(2)//[]
Object.entries
同 keys
var obj = { foo: 'bar', baz: 42 }; var map = new Map(Object.entries(obj)); map // Map { foo: "bar", baz: 42 }
es7的提案,試了下,在chrome 52中不能識別
let { x, y, ...z } = null; // 運行時錯誤 let { ...x, y, z } = obj; // 句法錯誤
淺拷貝
let obj = { a: { b: 1 } }; let { ...x } = obj; obj.a.b = 2; x.a.b // 2
不會拷貝繼承自原型對象的屬性
function baseFunction({ a, b }) { // ... } function wrapperFunction({ x, y, ...restConfig }) { // 使用x和y參數進行操做 // 其他參數傳給原始函數 return baseFunction(restConfig); }
let z = { a: 3, b: 4 }; let n = { ...z }; n // { a: 3, b: 4 } // 等同於 let aClone = Object.assign({}, a); let ab = { ...a, ...b }; // 等同於 let ab = Object.assign({}, a, b); let newVersion = { ...previousVersion, name: 'New Name' // Override the name property }; let emptyObject = { ...null, ...undefined }; // 不報錯
擴展運算符的參數對象之中,若是有取值函數get,這個函數是會執行的。
// 並不會拋出錯誤,由於x屬性只是被定義,但沒執行 let aWithXGetter = { ...a, get x() { throws new Error('not thrown yet'); } }; // 會拋出錯誤,由於x屬性被執行了 let runtimeError = { ...a, ...{ get x() { throws new Error('thrown now'); } } };
let 塊做用域內聲明,不存在變量提高,打破了typeof在es5語法中永不報錯,
{ typeof varmy // nodeJs端報錯,ReferenceError: varmy is not defined let varmy } typeof unbar //不報錯,結果undefined
不能重複聲明
{ var x = 1 let y = 2 } function foo(x=y, y=1){ return {x,y} }
const命令聲明時就需賦值,不然報錯,後續不能改值,若是指向對象,只要指向對象地址不變,均可以。其它同let。
若是想凍結對象,Object.freeze。
var constantize = (obj) => { Object.freeze(obj); Object.keys(obj).forEach( (key, value) => { if ( typeof obj[key] === 'object' ) { constantize( obj[key] ); } }); };
es5中兩種聲明變量,var function
es6中 新增let const class import
SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
瀏覽器端let const class聲明的變量,再也不是全局對象的屬性
瀏覽器端的模塊化方案AMD,NodeJs端的CommonJs;都是運行時加載。ES6的模塊化是編譯時加載。
with
語句arguments.caller
和arguments.callee
protected
、static
、interface
export var i = 1 export function fn(){} export class Person{} // 或者先定義,後扔出 export {i, fn, Person} // 重命名 export { i as j, fn as fn1, Person as Man }
export導出的變量,值是動態綁定的;export必須處於模塊的頂層,不然報錯
大括號裏的變量名和要導出文件裏的變量名要一致;或者使用as重命名。import具備命名提高效果。
import能夠只執行後面文件
import 'exec.js'
先導入後導出,能夠簡寫
import {yo} from "yo.js" export default yo // 簡寫後 export {yo as default} from "yo.js"
導出的時候,能夠只導出一個默認值,這樣import時,不用關心要導入文件的對應的方法名和變量名,import時,能夠取任一名字。
// yo.js function fn(){ //... } export default fn import method1 from 'yo.js'
除了這個特性外,default至關於一個特殊的名稱,擁有通常名稱所擁有的行爲。
// yo.js function fn(){ // ... } export {fn as default} import {default} from 'yo.js'
export default var a = 1;// 會報錯 export default function fn(){} import customName, { otherMethod } from './export-default'; export default 42; import * as obj from 'yo.js'
模塊的繼承
export * from 'yo.js'
export *
不會導出default
導出的變量,是動態的,變量的值變,導出的結果就變。若是導出是默認,默認值等於一個變量,變量的值變,默認值不變。若是導出的是個引用,不能對引用從新賦值
// lib.js export let obj = {}; // main.js import { obj } from './lib'; obj.prop = 123; // OK obj = {}; // TypeError