let && const
let與var的聲明用法相同,但是多了一個(gè)臨時(shí)死區(qū)(Temporal Distonrtion Zone)的概念。
console.log(a)// -> undefinedvara =1console.log(b)// -> Uncaught ReferenceError: b is not definedletb =1
可以發(fā)現(xiàn)在聲明前使用let聲明的變量會(huì)導(dǎo)致報(bào)錯(cuò),這解決了 JS 很多奇怪的問題。并且使用let會(huì)生成一個(gè)塊級(jí)作用域,作用域外不能訪問該變量。
{leta =1;varb =1;}console.log(b);// -> 1console.log(a);//? -> Uncaught ReferenceError: b is not defined
在 JS 中,聲明變量都會(huì)提升,不論用什么關(guān)鍵字聲明。當(dāng)使用let時(shí)變量也會(huì)被提升至塊級(jí)作用域的頂部,但是只提升聲明,不提升初始化。并且會(huì)產(chǎn)生臨時(shí)死區(qū),該區(qū)域會(huì)存放變量,直到執(zhí)行過聲明語句后,方可使用該變量。
在循環(huán)中l(wèi)et會(huì)與前面有些不同,每次迭代都會(huì)產(chǎn)生一個(gè)新的變量,并用之前的值初始化,如何理解這句話呢,請(qǐng)看以下代碼。
for(leti =0; i <10; i++) {console.log(i)// -> 輸入 0 - 9}// 上面的循環(huán)代碼可以這樣看{// 形成塊級(jí)作用域leti =0{letii = iconsole.log(ii)? ? }? ? i++? ? {letii = iconsole.log(ii)? ? }? ? i++? ? {letii = iconsole.log(ii)? ? }? ? ...}
const與let基本類似,只是用const聲明必須賦值,并且不得修改綁定,什么意思呢,請(qǐng)看代碼。
consta =1;a =2// -> Uncaught TypeError: Assignment to constant variable// butconstb = {a:1};b.a =2// 起效
當(dāng)然了,有辦法讓這個(gè)不能改變
constb =Object.freeze({a:1})b.a =2// 沒有報(bào)錯(cuò),但是 b.a 沒有被改變
但是Object.freeze只能在這里有效,對(duì)于數(shù)組這些可以看看這個(gè)提案。
這兩個(gè)新的聲明方式在全局作用域下不會(huì)自動(dòng)加上window
字符串相關(guān)
部分新增的字符串函數(shù)
letstring ='startend'string.includes('a')// -> true 是否包含string.endsWith('end')// -> true 是否由 end 結(jié)尾string.startsWith('start')// -> true 是否由 start 開頭
模板字面量
很棒的新功能,解決了之前很多麻煩的寫法。
// 語法就是 `` 代替之前的引號(hào),在 `` 中使用引號(hào)不需要轉(zhuǎn)義lets =`it's string`
多行字符串
// 這樣在語法中就可以換行了lets =`start \
end`// 注意在模板字面量中的任何空白符都是起效的lets =`start \
? ? end`// ->? start? ? end
占位符和標(biāo)簽?zāi)0?/p>
lets ='string'letmessage =`start${s}`// -> startstring// ${} 就是占位符語法,可以更簡(jiǎn)便的實(shí)現(xiàn)字符串插入// 定義一個(gè) tag 函數(shù),然后直接在 `` 前使用就可以letm = tag`s${s}e${message}`// strings 是一個(gè)數(shù)組,value 是模板字面量中所有的占位符的值functiontag(strings, ...value){// -> ['s', 'e', '']console.log(strings)// -> ['string', 'startstring']console.log(value)}// 上面的 ...value 也是 ES6新出的擴(kuò)展語句,在這里代表不定參數(shù)的寫法,用于替換 arguments// 不定參數(shù)使用上也是有限制的,必須放在所有參數(shù)的末尾,并且在每個(gè)函數(shù)中只能聲明一次// 擴(kuò)展語句和 arguments 區(qū)別就是代表了 strings 參數(shù)后面的所有參數(shù)// 除了上面的寫法,還可以用于展開可以迭代(有Symbol.iterator屬性)的對(duì)象letarray = [1,2,3]console.log(...array)// 該語法可以解決之前很多地方只能傳入單個(gè)參數(shù),只能使用 apply 解決的問題Array.prototype.unshift.apply([4,5], array)// -> [1, 2, 3, 4, 5]// 現(xiàn)在可以直接這樣寫[4,5].unshift(...array)// 展開運(yùn)算不受不定參數(shù)的條件限制,可以一起用
函數(shù)
默認(rèn)參數(shù)
ES6 允許給函數(shù)增加默認(rèn)參數(shù)
functionfn(a =1, b =2){}// 默認(rèn)值也可以通過調(diào)用函數(shù)獲得,注意必須調(diào)用函數(shù)functionfn1(a =1, b = fn()){}
新增函數(shù)內(nèi)部方法
在 JS 中,函數(shù)有多種用法,可以直接調(diào)用,也可以通過new構(gòu)造函數(shù)。
在 ES6中,函數(shù)內(nèi)部新增了 [[Call]] 和 [[Construct]] 兩個(gè)方法。后者會(huì)在使用new構(gòu)造函數(shù)時(shí)執(zhí)行,其他情況會(huì)執(zhí)行前者方法。
當(dāng)一個(gè)函數(shù)必須使用new構(gòu)造時(shí),你可以使用這個(gè)新屬性new.target判斷
// new.target 只能在函數(shù)中使用functionFn(){if(typeofnew.target ==='underfined') {throw....... }}
箭頭函數(shù)
這個(gè)特性真的很棒,先介紹下他的幾種語法
// 最簡(jiǎn)單的寫法,只有一個(gè)參數(shù),單行表達(dá)式value => value// 多個(gè)參數(shù)需要使用小括號(hào)包裹(v1, v2) => v2 + v1// 沒有參數(shù)需要使用小括號(hào)包裹() =>"balabala"http:// 多行表達(dá)式需要大括號(hào)包裹(v1, v2) => {returnv1 + v2}// 返回一個(gè)對(duì)象,需要用小括號(hào)包裹() => ({a:1})// 立即執(zhí)行函數(shù),注意普通的立即執(zhí)行函數(shù)的小括號(hào)包裹在最外面,箭頭函數(shù)不需要((value) =>value)("balabala")
箭頭函數(shù)和普通函數(shù)區(qū)別還是蠻大的,說幾個(gè)常用的
沒有this,不能改變this綁定
不能通過new調(diào)用,當(dāng)然也沒有原型
沒有arguments對(duì)象,不能有相同命名參數(shù)
箭頭函數(shù)雖然沒有this,但是還是可以在內(nèi)部使用this的
this的綁定取決于定義函數(shù)時(shí)的上下文環(huán)境
一旦函數(shù)調(diào)用,任何改變this的方法都無效
// let 有個(gè)細(xì)節(jié)letx =11111leta = {x:1,? ? init() {// 箭頭函數(shù)的 this 取決于 init,所以可以打印出 1document.addEventListener('click', () =>console.log(this.x))? ? },allowInit:()=>{// allowInit 直接是個(gè)箭頭函數(shù),所以這時(shí)的 this 變成了 window// 但是并不會(huì)打印出 11111,忘了 let 的一個(gè)細(xì)節(jié)的可以回到上面看看console.log(this.x))? ? }? ? otherInit() {// 普通函數(shù)的 this 取決于調(diào)用函數(shù)的位置,this 指向 document// 如果想打印出 x,可以使用 binddocument.addEventListener('click',function(){console.log(this.x)? ? ? ? })? ? }}a.init()// -> 1a.allowInit()// -> undefineda.otherInit()// -> undefined
對(duì)象相關(guān)
leta =1// 當(dāng) key 和 value 名字相同時(shí)可以簡(jiǎn)寫letb = { a }// 對(duì)象中的方法也可以簡(jiǎn)寫leta = {? ? init() {}}// 對(duì)象屬性名也可以計(jì)算 letname ='name'b[name +'1'] =2// === b['name1'] = 2
ES6 也新增了幾個(gè)對(duì)象方法
Object.is(NaN,NaN)// ->true// 結(jié)果基本于 === 相似,除了 NaN 和 +0 -0Object.is(+0,-0)// -> falseleto = {a:1}leta =Object.assign({}, o)// -> {a: 1}// 第一個(gè)參數(shù)為目標(biāo)參數(shù),后面的參數(shù)是不定的,參數(shù)屬性名如果有重復(fù),后面的會(huì)覆蓋之前的
原型相關(guān)
ES6 之前改變對(duì)象原型很麻煩
letobj = {a:1}letobj1 = {a:2}// 已 obj 為原型leta =Object.create(obj)// 改變 a 的原型為 obj1Object.setPrototypeOf(a, obj1)// a.a === 2
訪問原型
Object.getPrototypeOf(a)// 訪問原型// ES6 中可以直接通過 super 代表原型leta = {? ? init() {return'Hello'}}letb = {? ? init() {// 不能在 super 之前訪問 thisreturnsuper.init() +'World'}}Object.setPrototypeOf(b, a)b.init()// -> 'HelloWorld'
但是 super 不是每個(gè)函數(shù)都可以使用的,只有在函數(shù)的簡(jiǎn)寫語法中方可使用。因?yàn)樵?ES6中新增了一個(gè)函數(shù)內(nèi)部屬性 [[HomeObject]],這個(gè)屬性決定了是否可以訪問到super。首先在該屬性上調(diào)用Object.getPrototypeOf(綁定的對(duì)象),然后找到原型中的同名函數(shù),在設(shè)置this綁定并且調(diào)用函數(shù),其實(shí)就是一個(gè)新增的語法糖。
解構(gòu)賦值
該特性可以用于對(duì)象,數(shù)組和傳參。
letobj = {a:1,b:2}// 對(duì)象解構(gòu)使用 {},數(shù)組解構(gòu)使用 [],因?yàn)檫@里是對(duì)象解構(gòu),c 不是 obj 的屬性,所以 underfined// 數(shù)組解構(gòu)中,如果需要解構(gòu)的變量大于數(shù)組索引,多出來的變量也是 undefined// 解構(gòu)必須賦值,否則報(bào)錯(cuò)。不能 let {a, b, c};// 賦值不能為 null 或者 undefined,會(huì)報(bào)錯(cuò)let{a, b, c} = obj// 等于 let a = obj.a,可以看做之前介紹的對(duì)象屬性簡(jiǎn)寫console.log(a, b, c)// -> 1, 2, underfined// 如果已經(jīng)聲明了變量并且想使用解構(gòu),必須最外面是小括號(hào)({a, b} = obj)// 如果不想使用 obj 中的對(duì)象名,又想使用解構(gòu)賦值let{x: a} = obj// 如果想使用默認(rèn)值let{a =2, c=3} = obj// -> 1, 3// 因?yàn)?a 是 obj 中的對(duì)象,所以默認(rèn)值被覆蓋// 解構(gòu)也可以嵌套letobj = {data: {code:1},message: [1,2]}// 這個(gè)寫法在 json 中很好用// 注意在這個(gè)寫法中,data 和 message 都是指代了 obj 的屬性,并沒有被聲明變量let{data: {code},message: [a] } = objconsole.log(code, a)// 數(shù)組解構(gòu)和對(duì)象解構(gòu)基本相似,并且簡(jiǎn)單多了letmessage = [1,2,3,4]// 因?yàn)閿?shù)組取值只能索引取,所以想跳過某幾個(gè)索引,就用逗號(hào)代替// 同樣,數(shù)組解構(gòu)也可以使用默認(rèn)值和嵌套解構(gòu),和對(duì)象解構(gòu)一模一樣就不贅述了let[a, , b] = message// -> 1, 3// 在上面章節(jié)介紹了擴(kuò)展語法,同樣也可以使用在數(shù)組解構(gòu)中// 可以看到 b 變成了一個(gè)數(shù)組let[a, ...b] = message// -> 1, [2, 3, 4]// 傳參使用解構(gòu)可以讓要傳的參數(shù)更加清晰functionfn(name, {key, value}){console.log(name, key, value)}// 使用,注意:傳參解構(gòu)必須起碼傳入一個(gè)值,否則報(bào)錯(cuò)fn(1, {key:2,value:3})// 因?yàn)閭鲄⒔鈽?gòu)類似以下寫法functionfn(name, {key, value}){let{key, value} =null// 這個(gè)上面講過不能這樣寫}
Symbol
ES6 新出的第六個(gè)原始類型。多用于避免代碼沖突,作為一個(gè)私有屬性使用,不會(huì)被屬性遍歷出來??梢允褂肙bject.getOwnPropertySymbols()檢索 Symbol 屬性。
創(chuàng)建和使用
// 創(chuàng)建leta =Symbol()// 更推薦這種寫法,可以更加明確這個(gè)Symbol的用途// 并且有函數(shù)可以通過這個(gè)字符串取到相應(yīng)的Symbolletb =Symbol('is b')// 使用,一般作為可計(jì)算屬性使用leta = {}letb =Symbol('is b') a[b] =1// 可以在全局注冊(cè)表中共享同一個(gè) Symbol,但不推薦使用// 不存在 is a 會(huì)自動(dòng)創(chuàng)建leta =Symbol.for('is a')
暴露內(nèi)部操作
Symbol 中預(yù)定義了一些 well-know Symbol,這些 Symbol 定義了一些語言的內(nèi)部實(shí)現(xiàn)
Symbol.hasinstance,用于執(zhí)行instanceof時(shí)檢測(cè)對(duì)象的繼承信息
Symbol.isConcatSpreadable,布爾值,用于判斷當(dāng)使用concat函數(shù)時(shí)是否將數(shù)組展開
Symbol.iterator,迭代器,后面會(huì)講到
Symbol.match,Symbol.replace,Symbol.search,Symbol.split,字符串相關(guān)方法的對(duì)應(yīng)內(nèi)部實(shí)現(xiàn)
Symbol.toPrimitive,返回對(duì)象原始值
Symbol.toStringTag,調(diào)用toString
Set 和 Map
Set
Set 是新增的無重復(fù)的有序集合,多用于集合去重或者判斷集合中是否含有某個(gè)元素。
// 創(chuàng)建letset =newSet()// 添加元素set.add(1)set.add('1')// 重復(fù)的元素不會(huì)被添加set.add(1)// 判斷是否包含元素set.has(1)// -> true// 判斷長(zhǎng)度set.size()// -> 2// 刪除某個(gè)元素set.delete()// 移除所有元素set.clear()
Map
Map 是新增的有序鍵值對(duì)列表,鍵值可以是任何類型。
// 創(chuàng)建letmap =newMap()// 設(shè)置鍵值對(duì)map.set('year',"2017")map.set({},'obj')// 取值map.get('year')// -> '2017'// 判斷是否有該鍵值map.has('year')// -> true// 獲得長(zhǎng)度map.size()// -> 2// 刪除某個(gè)鍵值map.delete('year')// 移除所有鍵值map.clear()
迭代器和 Generator 函數(shù)
迭代器
顧名思義,用來迭代的。之前介紹過Symbol.iterator,可以迭代的對(duì)象都有這個(gè)屬性,包括數(shù)組,Set,Map,字符串和 NodeList。ES6新增的for-of就用到了迭代器的功能,但是默認(rèn)只有上面這些對(duì)象能使用。
leta = [1,2]for(letvalueofa) {console.log(value)// -> 1, 2}// 上面的代碼其實(shí)就是調(diào)用了數(shù)組的默認(rèn)迭代器letiterator = a[Symbol.iterator]()// 當(dāng)調(diào)用 next 時(shí)會(huì)輸出這次迭代的 value 和是否迭代完成console.log(iterator.next())// {value: 1, done: false}console.log(iterator.next())// {value: 2, done: false}// 已經(jīng)沒元素可以迭代了console.log(iterator.next())// {value: undefined, done: true}// 數(shù)組的默認(rèn)迭代器只會(huì)輸出 value,如果想同時(shí)輸出索引的話// 這里可以使用新特性數(shù)組解構(gòu) let [index, value]for(letvalueofa.entries()) {console.log(value)// -> [0, 1]? [1, 2]}
對(duì)于自己創(chuàng)建的對(duì)象都是不可迭代的,當(dāng)然我們也可以讓他變成迭代的
leta = {array: [],// 這是一個(gè) Generator 函數(shù),馬上就會(huì)講到*[Symbol.iterator]() {for(letiteminthis.array) {yielditem? ? ? ? }? ? }}a.array.push(...[1,2,3])for(letitemofa) {console.log(item)}
Generator 函數(shù)
用于異步編程。該函數(shù)可以暫停和恢復(fù)執(zhí)行,和同步寫法很像。
// 星號(hào)表示這是一個(gè) Generator 函數(shù)function*gen(){// 第一次 next 只執(zhí)行到等號(hào)右邊letfirst =yield1// 第二次 next 執(zhí)行 let first = 和 yield 2letsecond =yield2// 不執(zhí)行接下來的 next 就卡在上一步了letthrid =yield3}letg = gen()g.next()// -> {value: 1, done: false}g.next()// -> {value: 2, done: false
接下來看下 Generator 函數(shù)如何用于異步
functiongetFirstName(){? ? setTimeout(function(){? ? ? ? gen.next('alex')? ? },1000);}functiongetSecondName(){? ? setTimeout(function(){? ? ? ? gen.next('perry')? ? },2000);}function*sayHello(){vara =yieldgetFirstName();varb =yieldgetSecondName();// settimeout 本來是異步的,通過 Generator 函數(shù)寫成了同步寫法console.log(a, b);// ->alex perry}vargen = sayHello();gen.next();
類
JS 中的類不是其他語言中的類,只是個(gè)語法糖,寫法如下。
classPerson{// 構(gòu)造函數(shù)constructor() {this.name = name? ? }? ? sayName() {console.log(this.name)? ? }}letp =newPerson('name')p.sayName()// -> 'name'// class 就是以下代碼的語法糖// 對(duì)應(yīng) constructorfunctionPerson(name){this.name = name}// 對(duì)應(yīng) sayNamePerson.prototype.sayName =function(){console.log(this.name)}
類聲明相比之前的寫法有以下幾點(diǎn)優(yōu)點(diǎn)
類聲明和 let 聲明一樣,有臨時(shí)死區(qū)
類聲明中的代碼全部運(yùn)行在嚴(yán)格模式下
必須使用 new 調(diào)用
繼承
在 ES6 之前寫繼承很麻煩,既然有個(gè)類,那么必然也可以繼承類了
classPerson{// 構(gòu)造函數(shù)constructor() {this.name = name? ? }? ? sayName() {console.log(this.name)? ? }}// extends 代表繼承自PersonclassStudentextendsPerson{constructor(name, age) {// super 的注意事項(xiàng)之前有說過super(name)// 必須在 super 之后調(diào)用 thisthis.age = age? ? }? ? sayName() {// 如果像使用父類的方法就使用這個(gè)方法使用// 不像使用的話就不寫 super,會(huì)覆蓋掉父類的方法super.sayName(this.name)console.log(this.age)? ? }}
Promise
概念
用于異步編程。
// 你可以使用 new 創(chuàng)建一個(gè) Promise 對(duì)象letpromise =newPromise(function(resolve, reject)){}resole()// 代表成功reject()// 代表失敗promise.then(onFulfilled, onRejected)// 當(dāng)調(diào)用 resole 或者 reject ,then 可以監(jiān)聽到promise.catch()// reject 或者 throw時(shí)可以監(jiān)聽到
Promise 有三個(gè)狀態(tài)
pending,等待狀態(tài),也就是既不是 resolve 也不是 reject 狀態(tài)
fulfilled,resolve 以后進(jìn)入這個(gè)狀態(tài)
reject,reject 以后進(jìn)入這個(gè)狀態(tài)
一般使用情況
functiondelay(){// 創(chuàng)建一個(gè) promisereturnnewPromise((resolve, reject) =>{// 當(dāng)調(diào)用 promise 時(shí),里面的內(nèi)容會(huì)立即執(zhí)行console.log('in delay')? ? ? ? setTimeout(()=>{? ? ? ? ? resolve(1)? ? ? ? },1000)? ? });}functionotherDelay(){returnnewPromise((resolve, reject) =>{? ? ? ? setTimeout(()=>{? ? ? ? ? reject(1)? ? ? ? },1000)? ? });}// 這里會(huì)先輸出 delay 函數(shù)中的 log,然后再輸出 outer,接下來1秒以后輸出3個(gè)1delay()// then 可以捕獲 resolve 和 reject.then((value) =>{console.log(value)? ? })console.log('outer')otherDelay()// 捕獲 reject時(shí),如果不需要捕獲 resolve 時(shí)可以這樣寫.then(null, (value) => {console.log(value)? ? })// 捕獲 reject 或者 throw 時(shí)推薦使用這個(gè)寫法,原因后面會(huì)說otherDelay()? ? .catch((value) =>{console.log(value);? ? })
以上是最常用的 Promise 寫法,現(xiàn)在介紹 Promise 鏈
delay()// then 會(huì)返回一個(gè)新的 promise 對(duì)象.then((value) =>{// 這樣就可以傳參了returnvalue +1}).then((value) =>{console.log(value)// -> 2// then 里面可以也可以傳入一個(gè)函數(shù)名,會(huì)自動(dòng)調(diào)用// 如果傳入的函數(shù)有參數(shù)會(huì)自動(dòng)傳入}).then(delay).then((value) =>{console.log(value)// -> 1// 如果在then 中拋出錯(cuò)誤,只有 catch 才能監(jiān)聽到,所以推薦使用 catch 監(jiān)聽錯(cuò)誤thrownewError('error')? ? }).then((value) =>{console.log(value)// 這個(gè)then 不會(huì)執(zhí)行}).catch((error) =>{console.log('catch'+ error)// -> catch Error})
Promise 高級(jí)用法
開發(fā)中可能會(huì)有需求,需要一次上傳幾張圖片,全部上傳成功以后有個(gè)提示,這時(shí)候就可以用到Promise.all()
functionupdateOne(){returnnewPromise((resolve, reject) =>{? ? ? ? setTimeout(()=>{? ? ? ? ? ? resolve('one')? ? ? ? ? ? },1000)? ? });}functionupdateTwo(){returnnewPromise((resolve, reject) =>{? ? ? ? setTimeout(()=>{? ? ? ? ? ? resolve('two')? ? ? ? ? ? },2000)? ? });}// all 函數(shù)接收一個(gè)可迭代對(duì)象,注意這里傳入函數(shù)必須調(diào)用letpromise =Promise.all([updateOne(), updateTwo()])// 只有當(dāng) all 中的異步全部完成了才會(huì)調(diào)用 thenpromise? ? .then((value) =>{// value 是個(gè)函數(shù),順序按照 all 里的迭代對(duì)象的順序console.log(value)// -> ["one", "two"]})
如果一個(gè)異步任務(wù)超時(shí)了,你想直接取消,可以通過Promise.race()
// 假設(shè)該任務(wù)執(zhí)行時(shí)間超過1秒就算超時(shí),應(yīng)該 cancelfunctiondelay(){returnnewPromise((resolve, reject) =>{? ? ? ? setTimeout(function(){? ? ? ? ? ? resolve('finish')? ? ? ? },1500);? ? });}functioncancel(){returnnewPromise((resolve, reject) =>{? ? ? ? setTimeout(function(){? ? ? ? ? ? resolve('cancel')? ? ? ? },1000);? ? });}// 接收的參數(shù)和 all 相同letpromise =Promise.race([delay(), cancel()])// race 中只要有一個(gè)任務(wù)完成,then 就會(huì)被調(diào)用,這樣就可以 cancel 掉所有超時(shí)任務(wù)promise? ? .then((value) =>{console.log(value)// -> cancel})
Proxy
Proxy 可以創(chuàng)建一個(gè)代替目標(biāo)對(duì)象的代理,攔截語言內(nèi)部的操作。
lethandle = {}lettarget = {}// 這樣就創(chuàng)建了target 對(duì)象的代理,但是這個(gè)代理其實(shí)沒有任何用處letp =newProxy(target, handle)
上面的代碼中可以看到傳入了一個(gè)handle的對(duì)象,只有當(dāng)這個(gè)對(duì)象中包含一些代理行為的函數(shù)時(shí),這個(gè)代理才有用。具有的代理行為函數(shù)可以去MDN查看,這里舉例幾個(gè)用法。
lethandle = {// 改變 set 的內(nèi)部操作set(target, key, value) {// 當(dāng)給 age 屬性賦值小于19時(shí)報(bào)錯(cuò)console.log(value)if(key ==='age') {if(value <19) {thrownewError('未成年')? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }? ? }lettarget = {}letp =newProxy(target, handle)p.age =1// -> 報(bào)錯(cuò)p.age =19// -> 沒問題
模塊化
ES6 引入了原生的模塊化,這樣就可以拋棄之前的 AMD 或者 CMD 規(guī)范了,如果對(duì)模塊化還沒什么了解,可以看下我之前的文章明白 JS 模塊化。
// example.js 文件下// export 可以導(dǎo)出任何變量,函數(shù)或者類exportvarage =14exportfunctionsum(n1, n2){returnn1 + n2}exportclassPerson{constructor(age) {this.age = age? ? }}// 別的 JS 文件中導(dǎo)入// 如果想導(dǎo)入整個(gè)模塊并且自己命名,就可以這樣使用// import 后面代表模塊名,from 后面代表要導(dǎo)入的文件地址import*asExamplefrom'./example'console.log(Example.age)// -> 14// 當(dāng)然你也可以只使用模塊中的一個(gè)功能// 這里使用了對(duì)象解構(gòu)的方法拿到需要的功能,注意這里名字必須相同,否則使用會(huì)報(bào)錯(cuò)import{ age, sum }from'./example'console.log(age)// -> 14console.log(sum(1,2))// -> 3// 現(xiàn)在我只想導(dǎo)出一個(gè)功能,并且外部可以隨便命名該如何做呢?// default 一個(gè)文件中只能使用一次exportdefaultvarage =14// MyAge 可以隨便自己喜歡命名importMyAgefrom'./example'console.log(MyAge)// -> 14