成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

寫了個插件,一口氣解決項目中所有精度丟失問題!

開發 前端
當我們擁有了decimal.js之后,每當我們進行運算的時候,就必須引入它進行使用,每一個頁面都得重復這一操作,于是萌生了一個想法——我想自動!不想手動!

前言

大家好,我是林三心,用最通俗易懂的話講最難的知識點是我的座右銘,基礎是進階的前提是我的初心。

JS 繞不開的精度丟失問題

在 javascript 中,當我們進行運算時

0.1 + 0.2

你覺得輸出是 0.3 嗎?顯然不是的,由于 javascript 存在精度丟失問題,導致了輸出的不是你預期的

圖片圖片

image.png

至于為什么會精度丟失呢?我之前出過一篇文章專門講了這個原因你知道 0.1+0.2 !==0.3是進制問題,但你講不出個所以然,是吧???,感興趣的朋友可以看看,由于這不是本文的重點,所以我在這就不過多講解~

解決精度丟失的方案?

我會選擇使用 decimal.js 這個庫,文檔在 文檔,他的基本使用如下:

// 先安裝
npm install decimal.js

// 后使用
const Decimal = require('decimal.js');

new Decimal(0.1).add(0.2) // 加法 輸出 0.3
new Decimal(0.1).sub(0.2) // 減法
new Decimal(0.1).mul(0.2) // 乘法
new Decimal(0.1).div(0.2) // 除法

使用 decimal.js進行運算,能解決精度丟失的問題~

不想手動!想自動!

很煩??!

當我們擁有了decimal.js之后,每當我們進行運算的時候,就必須引入它進行使用,每一個頁面都得重復這一操作,于是萌生了一個想法——我想自動!不想手動!

思路

那要怎么才能自動呢?由于前段時間群里很多人說想學習寫 babel 插件,所以剛好,針對這個需求,我可以實現一個 babel 插件,它的功能是:將項目中 0.1 + 0.2 這種表達式,轉換為 new Decimal(0.1).add(0.2)

0.1 + 0.2
// 轉換為
new Decimal(0.1).add(0.2)

這樣就能一次性把項目中的精度丟失問題解決了~

開發 babel 插件

前置準備

涉及到三個問題:

  • webpack 和 rollup 如何選擇
  • rollup 打包環境的搭建
  • 如何發布到 npm 上

這三個問題具體我在上一篇文章【如何使用Rollup開發一個npm包并發布】里有提到過了,在本文我就不過多講解

搭建一個 Rollup 打包環境

新建一個 babel-plugin-sx-accuracy文件夾,用來開發 babel 插件

名字可以自己取,但是為了規范,最好是 babel-plugin- 開頭

接著進入 babel-plugin-sx-accuracy 文件夾,輸入

npm init
npm i rollup @rollup/plugin-babel -D
npm i decimal.js -S

package.json 中的內容為:

"name": "babel-plugin-sx-accuracy",
  "version": "1.0.20",
  "description": "",
  "main": "dist/index.js",
  "type": "module",
  "scripts": {
    "build": "rollup -c"
  },
  "files": [
    "dist/*",
    "src/*"
  ],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@rollup/plugin-babel": "^6.0.3",
    "rollup": "^3.26.2"
  },
  "dependencies": {
    "decimal.js": "^10.4.3"
  }
}

然后在根目錄下新建 rollup.config.js 文件,用來配置 rollup 打包

// rollup.config.js
import babel from '@rollup/plugin-babel';

export default {
  input: 'src/index.js',
  output: {
    file: 'dist/index.js',
    format: 'cjs',
  },
  plugins: [
    babel({
      babelHelpers: 'bundled',
    }),
  ],
};

最后新建 src/index.js,我們的插件邏輯就寫在這里

圖片圖片

什么是抽象語法樹(AST)?

我們可以借助一個網站,來一睹抽象語法樹的真容~ https://astexplorer.net/

圖片圖片

這里我們可以記住幾個點

  • 每一個代碼片段都有屬于自己的節點類型
  • 代碼最外層的節點類型為 Program
  • 像 0.1+0.2 這種表達式,節點類型為 BinaryExpression
  • BinaryExpression節點里會有幾個重要的東西

operaor:運算符號

left:左邊的數字

right:右邊的數字

其實抽象語法樹的節點類型有很多種,我列舉一些:

  • 標識符(Identifier):表示變量、函數名等標識符的節點
  • 字面量(Literal):表示字面量值,如字符串、數字、布爾值等
  • 表達式語句(ExpressionStatement):表示包含表達式的語句節點
  • 賦值表達式(AssignmentExpression):表示賦值操作的表達式節點,如 x = 5
  • 二元表達式(BinaryExpression):表示包含二元操作符的表達式節點,如 x + y
  • 一元表達式(UnaryExpression):表示包含一元操作符的表達式節點,如 -x
  • 函數聲明(FunctionDeclaration):表示函數聲明的節點,包括函數名、參數和函數體
  • 變量聲明(VariableDeclaration):表示變量聲明的節點,包含變量名和可選的初始值
  • 條件語句(IfStatement):表示 If 條件語句的節點,包括條件表達式、if 分支和可選的 else 分支
  • 循環語句(WhileStatement、ForStatement):表示循環語句的節點,分別代表 While 循環和 For 循環
  • 對象字面量(ObjectLiteral):表示對象字面量的節點,包含對象屬性和屬性值
  • 數組字面量(ArrayLiteral):表示數組字面量的節點,包含數組元素
  • 函數調用(CallExpression):表示函數調用的節點,包含調用的函數名和參數列表
  • 返回語句(ReturnStatement):表示返回語句的節點,包含返回的表達式

當然大家現階段不需要去記,大家只需要記得這兩個類型就行了:

  • 代碼最外層的節點類型為 Program
  • 像 0.1+0.2 這種表達式,節點類型為 BinaryExpression

其實,我們平時在 webpack 開發時會接觸到一系列的插件,他們的功能比如有

  • 去除 console.log
  • 壓縮代碼
  • 去除注釋

其實他們的原理整體上都是一致的,分為三步:

  • 第一步:將代碼轉換成抽象語法樹
  • 第二步:使用 babel 為我們提供的方法,對語法樹進行增刪改查
  • 第三步:將處理后的語法樹重新轉換成代碼

而我們將要開發的插件,也是用到這個過程,但是第一步和第三步我們不需要管,我們只需要完成第二步中的增刪改查操作即可~

注意點:在第二步中,babel 會對抽象語法樹進行深度遍歷,遍歷到目標節點后,又會重新回到上層節點去重新遍歷下一個目標節點,所以一個節點會被遍歷兩次,一來一回 進去是 enter 回去是 exit

圖片圖片

插件基本代碼結構

下文使用 AST 來表達抽象語法樹

export default function ({ template: template, types: t }) {

  return {
    visitor: {
      Program: {
        exit: function (path) {
        }
      },
      BinaryExpression: {
        exit: function (path) {
        }
      }
    }
  }
}

開發一個 babel 插件,文件必須默認返回一個函數,接收一個對象參數,里面有個屬性我們需要用到

  • template: 是@babel/template的一個方法,他能使用模板的方式生成AST節點

函數內部的東西,我們也介紹下

  • vistor: 你可以理解為修改AST節點的入口
  • Program、BinaryExpression: 你需要修改的AST節點類型
  • exit: 就是剛剛說的 一來一回 中的,回
  • path: 就是被遍歷到的AST節點對象

插件完全實現

// 定義構造函數的名稱常量
const DECIMAL_FUN_NAME = 'Decimal'
// 運算符號映射 decimal.js 的四個方法
const OPERATIONS_MAP = {
  '+': 'add',
  '-': 'sub',
  '*': 'mul',
  '/': 'div'
}
// 運算符號數組
const OPERATIONS = Object.keys(OPERATIONS_MAP)

export default function ({ template: template }) {
  
  // require decimal.js 的節點模板
  const requireDecimalTemp = template(`const ${DECIMAL_FUN_NAME}=require('decimal.js')`);
  // 將運算表達式轉換為decimal函數的節點模板
  const operationTemp = template(`new ${DECIMAL_FUN_NAME}(LEFT).OPERATION(RIGHT).toNumber()`);

  return {
    visitor: {
      Program: {
        exit: function (path) {
          // 調用方法,往子節點body
          // 中插入 const Decimal = require('decimal.js')
          // 表達式
          path.unshiftContainer("body",
          requireDecimalTemp())
        }
      },
      BinaryExpression: {
        exit: function (path) {
          const operator = path.node.operator;
          if (OPERATIONS.includes(operator)) {
            // 調用方法替換節點
            path.replaceWith(
              // 傳入 operator left right
              operationTemp({
                LEFT: path.node.left,
                RIGHT: path.node.right,
                OPERATION: OPERATIONS_MAP[operator]
              })
            )
          }
        }
      }
    }
  }
}

打包 & 發布 NPM

當開發完成后,我們先 npm run build進行打包

然后運行 npm publish 發布到 NPM 上

圖片圖片

項目使用

首先安裝 babel-plugin-sx-accuracy

npm i babel-plugin-sx-accuracy

只需要在項目中的 .babelrc 或者 babel.config.js 中加入 babel-plugin-sx-accuracy即可

{
  "presets": ["@babel/preset-env"],
  "plugins": ["babel-plugin-sx-accuracy"]
}

我們來試試,一開始代碼是

console.log(0.1 + 0.2)
console.log(0.3 - 0.1)
console.log(0.2 * 0.1)
console.log(0.3 / 0.1)

打包后我們看看產物,并且輸出的也都是沒有精度丟失的結果?。。?/p>

圖片圖片

責任編輯:武曉燕 來源: 前端之神
相關推薦

2021-06-08 22:43:07

IPC方式Qt

2021-03-29 12:22:25

微信iOS蘋果

2020-10-22 12:30:33

MySQL

2023-12-18 23:09:25

開源優化引擎

2020-03-31 08:12:25

Kafka架構數據庫

2021-05-18 09:03:16

Gomapslice

2021-12-06 08:30:49

SpringSpring Bean面試題

2025-05-14 01:55:00

FCMCPAI

2020-04-14 13:32:56

@Transacti失效場景

2020-09-24 09:08:04

分布式系統架構

2021-03-01 18:52:39

工具在線瀏覽器

2022-05-24 11:50:46

延時消息分布式

2020-10-21 06:39:21

CPU寄存器架構

2020-07-08 07:45:44

OAuth2.0授權

2024-01-29 00:29:49

通信技術行業

2022-08-14 15:40:55

表情DIY

2021-01-04 11:23:21

手機無線電通訊

2024-03-26 09:42:27

分片算法應用

2024-03-28 12:52:00

AI模型

2020-04-16 12:42:42

附近的人共享單車App
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美一区二区三区四区视频 | 久久综合久色欧美综合狠狠 | 欧美一区二区三区视频 | 日韩精品一区二区三区四区视频 | wwww.8888久久爱站网 | 国产一区免费视频 | 日韩在线中文字幕 | 爽爽免费视频 | 免费亚洲成人 | 成在线人视频免费视频 | 一级a性色生活片久久毛片波多野 | 午夜av免费 | 男人的天堂视频网站 | 国产无人区一区二区三区 | 亚洲精品国产成人 | 天天操人人干 | 精品福利在线 | 国产精品爱久久久久久久 | 日韩欧美一区二区三区免费看 | 日韩一区二区三区精品 | 日韩三级 | 五月婷婷激情 | 天天看天天爽 | 欧美日韩中文字幕在线播放 | 国产成人精品久久二区二区91 | 亚洲在线一区二区 | 成人免费黄视频 | 国产成人精品午夜 | 国产精品免费大片 | 一级片网址 | 视频一二三区 | 国产伦精品一区二区三区精品视频 | 日韩久久久一区二区 | 国产电影精品久久 | 涩涩视频网站在线观看 | 黄色大片免费观看 | 成人性生交大片免费看中文带字幕 | 亚洲欧美一区二区三区在线 | 51ⅴ精品国产91久久久久久 | 91资源在线播放 | 国产精品国产三级国产aⅴ中文 |