<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          JS語言特性(下)

          共 11574字,需瀏覽 24分鐘

           ·

          2021-09-28 12:22

          作者:小壞壞

          來源:SegmentFault 思否社區(qū)

          調(diào)包

          即引用其他項目或者文件。

          之所以需要把這個模塊單獨拎出來,是因為,一個語言能不能成氣候的其中的一個關(guān)鍵點在于能否模塊化;一個項目能否形成一個可觀的體量也離不開模塊化,簡單來說就是不同文件或項目間能否互相調(diào)用,es5和es6中都有著不同風(fēng)格的引用方式,開發(fā)時要注意自己的開發(fā)環(huán)境以及語法格式

          es5

          有著AMD、CMD、CommonJS三種的引用方式,其中AMD(Asynchronous Module Definition),CMD(Common Module Definition),是為了解決前端同步引用的過高延遲會產(chǎn)生的“假死”狀態(tài)而誕生的異步引用方式。

          就本人而言,前端開發(fā)已基本上全面使用es6格式語法,AMD、CMD格式的引用幾乎不用,此處不做詳細(xì)講解,詳情查看鏈接,只講解后端常用的CommonJS

          CommonJS的發(fā)展歷史在此:https://zhuanlan.zhihu.com/p/113009496

          CommonJS,導(dǎo)出有著exportsmodule.exports兩種方式,二者是完全等效的,但是絕大部分時候,為和es6的export區(qū)分開,只使用module.exports

          調(diào)用過程

          CommonJS的調(diào)用為同步調(diào)用,在調(diào)用時,執(zhí)行調(diào)用文件中的全部可執(zhí)行的部分;同步引用在后端可以忽略傳輸?shù)臅r延,但是前端同步+高延遲意味著瀏覽器要卡著等待接收到這個文件才能繼續(xù)進(jìn)行,這便有了上文提到的異步加載方式AMD和CMD

          //fileA.js 導(dǎo)出
          console.log("haoye1")
          function a(){
              console.log("haoye2")
          }
          a();
          module.exports={a}

          //b.js 引入
          const fileA=require("fileA")
          // 控制臺輸出:
          // haoye1
          // haoye2


          基本用法

          代碼如下

          //fileA.js 導(dǎo)出
          function a(){
              console.log("haoye")
          }
          const b=()=>{
              console.log("haoyeB")
          }
          const c=0;
          module.exports={//本質(zhì)上是將需要導(dǎo)出的值包裹成json變量賦予modules.exports
              a:a,
              b,//json格式若變量key和value的名字一樣可以直接縮寫
              c
          }
          //b.js 引入
          const fileA=require("fileA")
          fileA.a();//haoye
          fileA.b();//haoyeB
          //或者
          const {a,b}=require("fileA")
          a();//haoye
          b();//haoyeB


          值調(diào)用

          引用值時,是以變量的形式引入的(letconstvar),所以引用后的變量是否可修改以變量的定義為準(zhǔn),一般建議以const格式引用;

          在調(diào)用一般類型的參數(shù)(numberboolean等)為深拷貝,模塊內(nèi)的變量與引用后的變量無關(guān)聯(lián);但是在調(diào)用object類型參數(shù)時為淺拷貝,模塊內(nèi)變量與引用后的值是同步的;

          // b.js
          let count = 1//number類
          let obj = {//object類
              count: 1
          }
          let plusCount = () => {
              count++
          }
          let plusCount2 = () => {
              obj.count++
          }
          setTimeout(() => {
              console.log(count)//(1s后)2
              console.log(obj.count)//(1s后)2
          }, 1000)
          module.exports = {
              obj,
              count,
              plusCount
          }

          // a.js
          let mod = require('./b.js')
          console.log(mod.count)//1
          console.log(mod.obj.count)//1
          mod.plusCount()
          mod.plusCount2()
          console.log(mod.count)//1
          console.log(mod.obj.count)//2
          setTimeout(() => {
              mod.count = 3
              mod.obj.count = 3
              console.log(mod.count)//(2s后)3
              console.log(mod.obj.count)//(2s后)3
          }, 2000)

          es6

          es6的導(dǎo)出為export

          調(diào)用過程

          同CommonJS,為同步調(diào)用,調(diào)用時先執(zhí)行調(diào)用文件中的全部可執(zhí)行的部分

          基本用法

          有多行導(dǎo)出、統(tǒng)一導(dǎo)出、默認(rèn)導(dǎo)出三種格式

          // fileA.js
          // 多行導(dǎo)出
          export function a() {
            console.log("haoye")
          }
          export const b = () => {
            console.log("haoyeB")
          }
          // fileB.js
          // 統(tǒng)一導(dǎo)出
          function a() {
            console.log("haoye")
          }
          const b = () => {
            console.log("haoyeB")
          }
          export {
              a,
              b
          }
          // fileC.js
          // 默認(rèn)導(dǎo)出
          function a() {
            console.log("haoye")
          }
          const b = () => {
            console.log("haoyeB")
          }
          export default {//此種導(dǎo)出方式只能全部調(diào)用,不可只調(diào)用其中某個函數(shù)
              a,
              b
          }
          // fileD.js 導(dǎo)入演示
          import { a, b } from 'fileA'//或fileB
          a();//haoye
          b();//haoyeB

          // fileE.js 導(dǎo)入演示
          import D from 'fileD'
          import { a, b } from 'fileD'// 報錯
          D.a();//haoye
          D.b();//haoyeB


          值調(diào)用

          默認(rèn)所有的值以const變量形式引入(即不可修改),但同樣可將object類型變量內(nèi)的數(shù)據(jù)加以修改,并在原模塊內(nèi)依然產(chǎn)生影響

          // fileA.js
          export let counter = {
            count: 1
          }
          // fileB.js
          import { counter } from 'fileA'
          counter.count++;
          console.log(counter.count)//2
          counter = {}// 報錯: "counter" is read-only

          異步

          回調(diào)

          為保證某一函數(shù)的正常執(zhí)行,需要在其執(zhí)行完畢后對其結(jié)果進(jìn)行判斷,而判斷這個過程所執(zhí)行的函數(shù)即為回調(diào)函數(shù)

          例如一個簡單的a+b的函數(shù),通常情況下,我們可能會這么寫:

          function onSuccess(result){
              console.log("haoye ", result)
          }
          function onFailed(error){
              console.log("huaiye ", error)
          }
          function aPlusB(a,b){
              const c=a+b
              if(c===(Number(a)+Number(b))){//防止a或b為其他類型如字符串,在此驗證
                  onSuccess(c)
              }else{
                  onFailed(c)
              }
          }
          const a=1,b=2;
          aPlusB(a, b);// haoye 3

          但是當(dāng)我想把這個功能獨立成模塊,隨時隨地都可以處理其結(jié)果時,我們可能會這么寫:

          const a=1,b=2;
          function aPlusB(a,b){
              const c=a+b
              return c
          }
          const c=aPlusB(a, b);
          if(c===(Number(a)+Number(b))){
              onSuccess(c)
          }else{
              onFailed(c)
          }


          可隨意處理其結(jié)果的代價便是,必須要將結(jié)果返回,且判斷語句必須寫在外面;但也許可以這樣寫

          function aPlusB(a,b){
              const c=a+b
              if(c===(Number(a)+Number(b))){//防止a或b為其他類型如字符串,在此驗證
                  return {c,succes:true}
              }else{
                  return {c,succes:false}
              }
          }
          const a=1,b=2;
          const res=aPlusB(a, b);
          if(res.succes){
              onSuccess(res.c)
          }else{
              onFailed(res.c)
          }


          肉眼可見的降低了程序的可讀性,并且同樣需要等待函數(shù)執(zhí)行完,否則無法執(zhí)行接下來可能有的b+c,c+d等函數(shù),若接下來要執(zhí)行的函數(shù)根本用不到上一步所計算出的結(jié)果,那么等待便是完全無意義的

          js中的回調(diào)

          不過好在js可以以參數(shù)的形式聲明一個函數(shù),這樣就不需要等待回調(diào)也執(zhí)行完,才執(zhí)行下一步函數(shù),于是有如下寫法

          function aPlusB(a,b,onSuccess,onFailed){
              const c=a+b
              if(c===(Number(a)+Number(b))){//防止a或b為其他類型如字符串,在此驗證
                  onSuccess(c)
              }else{
                  onFailed(c)
              }
          }
          function onSuccess(result){
              console.log("haoye ", result)
          }
          function onFailed(error){
              console.log("huaiye ", error)
          }
          const a=1,b=2;
          aPlusB(a,b,onSuccess,onFailed)


          可以簡化為es6的箭頭函數(shù)形式

          aPlusB(a,b,(result)=>{
              console.log("haoye ", result)
          },(error)=>{
              console.log("huaiye ", error)
          })


          這樣以來,就不影響接下來的b+c,c+d了,并且回調(diào)函數(shù)的定義也更加的靈活;

          但現(xiàn)在又有了另一個問題,如果我接下來的b+c需要用到這一步的結(jié)果,比如我需要求a+b+c,那么我可能要這么寫

          const c=3
          aPlusB(a,b,(result)=>{
              aPlusB(result,c,(result2)=>{
                  console.log("haoye ", result2)
              },(error)=>{
                  console.log("huaiye ", error)
              })
          },(error)=>{
              console.log("huaiye ", error)
          })


          這是只需要+c的情況,但是如果我需要求a+b+c+d+e+f...呢?粗略展示下代碼

          const c=3,d=4,e=5
          aPlusB(a,b,(res)=>{
              aPlusB(res,c,(res2)=>{
                 aPlusB(res2,d,(res3)=>{
                     aPlusB(res4,e,(res4)=>{
                         aPlusB(res4,f,res5=>{
                             console.log("haoye ", res5)
                         },err=>{
                             console.log("huaiye ", err)
                         })
                     },err=>{
                         console.log("huaiye ", err)
                     })
                 },err=>{
                     console.log("huaiye ", err)
                 })
              },(err)=>{
                  console.log("huaiye ", err)
              })
          },(error)=>{
              console.log("huaiye ", err)
          })


          這就陷入了一種”回調(diào)地獄“,最直觀的來講,便是降低了代碼的可讀性和可維護(hù)性,使代碼變得臃腫、低效,例如err,其實只要其中任何一步丟出了錯誤,那么接下來全部的錯誤捕獲函數(shù)都是無意義的,但是為了程序的穩(wěn)定性,這些函數(shù)都必須要被定義,于是便有了es6中的——

          Promise

          中文翻譯過來便是承諾,意為在未來某一個時間點承諾返回數(shù)據(jù)給你。

          promise的詳細(xì)介紹在此:https://www.runoob.com/w3cnote/javascript-promise-object.html

          此處僅對promise的使用做簡單描述

          • Promise有三種狀態(tài):pending/reslove/reject 。pending就是未決,resolve可以理解為成功,reject可以理解為拒絕。

          • Promise常用的幾種方法 then 表示異步成功執(zhí)行后的數(shù)據(jù)狀態(tài)變?yōu)閞eslove, catch 表示異步失敗后執(zhí)行的數(shù)據(jù)狀態(tài)變?yōu)閞eject ,all表示把多個沒有關(guān)系的Promise封裝成一個Promise對象使用then返回一個數(shù)組數(shù)據(jù),finally表示無論成功還是失敗,全部執(zhí)行完畢。


          還是上面的a+b函數(shù),這次使用promise的方式來實現(xiàn)
          function aPlusB(a,b){
              return new Promise((onSuccess, onFailed)=>{
                  const c=a+b
                  if(c===(Number(a)+Number(b))){//防止a或b為其他類型如字符串,在此驗證
                      onSuccess(c)
                  }else{
                      onFailed(c)
                  }
              })
          }
          const a=1,b=2;
          aPlusB(a,b).then(res=>{//成功后執(zhí)行的函數(shù)
              console.log("haoye ", res)
          },err1=>{//失敗后執(zhí)行的函數(shù),可不定義,和catch至少有一個需要定義,否則拋出的錯誤無法捕獲
              console.log("huaiye ", err)
          }).catch(err2=>{//等效于上方的err1=>{},但是此處還可以抓取其他為能預(yù)測到的問題
              console.log("huaiye ", err2)
          })

          那么這種形式會如何應(yīng)對a+b+c+d+e+f...呢?
          const a=1,b=2,c=3,d=4,e=5
          aPlusB(a,b).then(res=>{//成功后執(zhí)行的函數(shù)
             return aPlusB(res, b)//若return為一般變量,則下一個then的res為改變量;若return為promise變量,則下一個res為該promise最終return的變量
          }).then(res=>{
              return aPlusB(res, c)
          }).then(res=>{
              return aPlusB(res, d)
          }).then(res=>{
              return aPlusB(res, e)
          }).then(res=>{
              return aPlusB(res, f)
          }).then(res=>{
              console.log("haoye ", res)
          }).catch(err=>{
              console.log("huaiye ", err)
          })

          優(yōu)勢很明顯,但問題也存在,當(dāng)拋出錯誤時,我們可能不知道錯誤具體在哪一步,但是可以通過在可能出錯的一步上添加onRejected回調(diào)
          但是 return new Promise((r,e)=>{})這種函數(shù)定義方式可能不是那么的優(yōu)雅,于是在即將推出的es7標(biāo)準(zhǔn)中(此功能目前的es6中已可以使用),新增asyncawait這兩個語法糖,可以使返回復(fù)雜的promise類以普通函數(shù)的形式編寫,以上函數(shù)可簡寫為
          async function aPlusB(a,b){
              const c=a+b
              if(c===(Number(a)+Number(b))){
                  return c// 正確則返回結(jié)果
              }else{
                  throw new Error(c)// 錯誤則拋出錯誤
              }
          }

          若希望此函數(shù)以同步的方式運(yùn)行則需要await關(guān)鍵詞
          const c=await aPlusB(a, b)

          但是await只能在異步函數(shù)中使用,只能對異步函數(shù)使用

          單線程

          js有著高效的運(yùn)行速度,但其卻是一種單線程語言,js的單線程運(yùn)行機(jī)制在此,但這也帶來了很多麻煩,因為服務(wù)器后臺有著多線程處理的剛需
          于是,nodejs為解決多線程的需求,在node10之后,有了穩(wěn)定的worker解決方案,但worker并沒有給js產(chǎn)生第二個線程,而是啟動了一個新的進(jìn)程,進(jìn)程之間使用json格式數(shù)據(jù)來進(jìn)行通訊


          點擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開更多互動和交流,掃描下方”二維碼“或在“公眾號后臺回復(fù)“ 入群 ”即可加入我們的技術(shù)交流群,收獲更多的技術(shù)文章~

          - END -


          瀏覽 22
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  九九九免费在线视频 | 亚洲1区2区3区4区5区 | 又粗又长又大一级a片免费看 | 亚洲欧美动漫中文字幕 | 一级a一级a爱片免费免免高潮 |