整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          javascript中如何解決精度丟失問題

          javascript中如何解決精度丟失問題

          項目開發中,你一定遇到過精度丟失的問題!比如某個無良的后端返回了一個超16位的數字訂單號,比如0.1+0.2 !=0.3等等:

          let a=0.1235678912345623456
          console.log(a)
          let b=256.1235678912345623456
          console.log(b)
          let c=0.1
          let d=0.2
          console.log(c + d)
          let e=2.55
          let f=1.55
          console.log(e.toFixed(1))
          console.log(f.toFixed(1))



          01

          精度丟失的原因

          是什么原因造成的捏?

          嗯?

          大道理咱也不會說,問就是一句話回復:

          在十進制轉二進制的過程中,因js存儲位數有限制,末位就會0舍1入取近似值,從而導致再轉回十進制時產生誤差。



          02

          如何解決


          • 使用toPrecision;
          • 乘以10的N次冪轉換成整數,再除以N次冪轉回小數;
          • 先加上1e-14或Number.EPSILON再取值;
          • 使用第三方庫,處理大數的 bignumber.js,處理小數的number-precision 和 decimal.js,處理JSON序列化json-bigint。

          使用toPrecision


          這個方法主要用于純展示。先用toPrecision保留一定位數的經度,再通過parseFloat展示。

          例如:

          console.log(parseFloat(0.30000000000000004.toPrecision(12)))

          這個12是精度默認值或者說是一個經驗值,12位一般都能解決0000...1和0000...9的問題。一般不適合浮點數的運算。


          先轉整數進行運算,再轉成小數


          這種方式是我之前浮點運算時經常用到的方法。我們拿0.1+0.2的運算來舉例:

          let a=(0.1*10 + 0.2*10) / 10
          console.log(a) //0.3

          但這種方法也不是萬能的,有時候也會失精:

          console.log(33.41*100) //3340.9999999999995
          console.log(2.55*100)  //254.99999999999997

          真是防不勝防啊!這時候我們也可以使用Math.round()方法來達到我們的目的,如下:

          console.log(Math.round(33.41*100))  //3341
          console.log(Math.round(2.55*100))  //255
          console.log((Math.round(0.1*10) + Math.round(0.2*10)) / 10)  //0.3

          先加上1e-14或Number.EPSILON再取值


          給浮點數加上一個極小的數就可以達到目的。獲取極小的數有兩種方式:

          • 1e-14(10的-14次方)
          • ES6的極小的常量Number.EPSILON


          先來看看Number.EPSILON是什么?

          console.log(Number.EPSILON)  //2.220446049250313e-16
          console.log(Number.EPSILON.toFixed(20))  //0.00000000000000022204

          這兩種方式都可以,看自己的喜好啦!

          let a=0.1235678912345623456
          console.log((a+1e-14).toFixed(1)) //0.1
          console.log((0.1 + Number.EPSILON + 0.2 + Number.EPSILON).toFixed(1))
          //0.3

          第三方庫

          第三方庫主要介紹以下四種:

          • bignumber.js的使用-處理大數

          安裝:

          npm install --save bignumber.js

          引入:

          import BigNumber from 'bignumber.js';

          使用:

          const a=new BigNumber(0.2);
          const b=new BigNumber(0.1)
          let c=a.plus(b)
          console.log(c) //BigNumber {s: 1, e: -1, c: Array(1)}
          console.log(c.toString())  //0.3
          console.log(c.toNumber())  //0.3

          官網:https://mikemcl.github.io/bignumber.js/


          • number-precision的使用-處理小數

          安裝:

          npm install number-precision --save

          引入:

          import NP from 'number-precision';

          使用:

          console.log(NP.strip(0.09999999999999998)); // 四舍五入:=0.1
          console.log(NP.round(0.105, 2)) //取2位小數,四舍五入:=0.11
          console.log(NP.plus(2.3, 2.6)); // 加:=4.9
          console.log(NP.minus(1.0, 0.9)); // 減:=0.1
          console.log(NP.times(3, 0.3)); // 乘:=0.9
          console.log(NP.divide(0.9, 0.3)); // 除:=3
          console.log(NP.plus(0.1, 0.2))


          • number-precision的使用-處理小數

          安裝:

          npm install --save decimal.js

          引入:

          import Decimal from "decimal.js"

          使用:

          console.log(Decimal(0.1).add(Decimal(0.2))); // 加: {s: 1, e: -1, d: Array(1), constructor: ?}
          console.log(Decimal(0.1).sub(Decimal(0.2))); // 減:{s: -1, e: -1, d: Array(1), constructor: ?}
          console.log(Decimal(0.1).mul(Decimal(0.2))); // 乘:{s: 1, e: -2, d: Array(1), constructor: ?}
          console.log(Decimal(0.1).div(Decimal(0.2))); // 除:{s: 1, e: -1, d: Array(1), constructor: ?}

          上面的結果是Decimal 對象,取值需要Number 或 String轉換

          官網:http://mikemcl.github.io/decimal.js/


          • json-bigint的使用-處理后端的返回值

          安裝:

          npm install json-bigint

          引入:

          import JSONBigInt from 'json-bigint';
          const JSONBigIntNative=JSONBigInt();

          使用:

          let json="{\"order\":258431607934229718,\"price\":1.258431607934229718,\"no\":123456}"
          const obj1=JSON.parse(json)
          const obj2=JSONBigIntNative.parse(json)
          console.log(obj1) //{order: 258431607934229730, price: 1.2584316079342297, no: 123456}
          console.log(obj2.order.toString())  //258431607934229718
          console.log(obj2.price.toString())  //1.258431607934229718
          console.log(obj2.order.toNumber())  //258431607934229730
          console.log(obj2.price.toNumber())  //1.2584316079342297

          主要是把大數據轉成字符串。其實關于這一點,如果后端經驗豐富的話,自然會給前端返回字符串,也無需前端轉換。不過呢,可能前端的技能的提升也就是從無經驗的后端開始的噢!

          oundation 可以很簡單的創建一個提醒框:

          提醒框可以使用 .alert-box 類創建, 可以添加可選的類: .secondary, .success, .info, .warning.alert:

          實例

          <div data-alert class="alert-box">

          This is a default alert box.

          </div>

          <div data-alert class="alert-box secondary">

          This is a secondary alert box.

          </div>

          <div data-alert class="alert-box success">

          <strong>Success!</strong> This alert box indicates a successful or positive action.

          </div>

          <div data-alert class="alert-box info">

          <strong>Info!</strong> This alert box indicates a neutral informative change or action.

          </div>

          <div data-alert class="alert-box warning">

          <strong>Warning!</strong> This alert box indicates a warning that might need attention.

          </div>

          <div data-alert class="alert-box alert">

          <strong>Alert!</strong> This alert box indicates a dangerous or potentially negative action.

          </div>


          圓角提醒框

          .radius.round 類用于為提醒框添加圓角:

          實例

          <div data-alert class="alert-box success radius">

          <strong>Success!</strong> Alert box with a radius.

          </div>

          <div data-alert class="alert-box info round">

          <strong>Info!</strong> Alert box that is rounded.

          </div>


          關閉提醒框

          要關閉提醒框,可以在連接或按鈕元素上添加 class="close" 類,并初始化 Foundation JS:

          實例

          <div data-alert class="alert-box">

          This is a default alert box with closing functionality.

          <a href="#" class="close">&times;</a>

          </div>

          <script>

          // Initialize Foundation JS For Functionality

          $(document).ready(function() {

          $(document).foundation();

          })

          </script>

          提醒框的寬度為容器的 100%。

          &times; (×) 是一個 HTML 字符實體表示一個關閉按鈕的圖標,而不是字母 "x"。

          /面包理想

          一轉眼已經2018年,前端行業也風風雨雨地走過了10多年,網頁布局也從最原始的文檔變成了精彩紛呈的交互。當我看到第四代CSS布局技術的時候,在驚嘆互聯網發展如此突飛猛進的同時,不禁會有一個疑問:CSS經歷1.0到3.0的版本變遷,最終又將走向哪里?

          今天我們就回顧一下CSS簡史和四次布局技術的躍遷。

          1.CSS簡史

          為什么我們需要回顧一下CSS簡史呢?

          1.了解過去能夠更好地預測未來,畢竟太陽底下沒有什么新鮮事。

          2.相比預測未來,通過了解CSS發展演變趨勢,能夠科學合理地評判CSS的發展,指導我們學習CSS的核心技術,讓我們在有限的精力和時間內學對知識,學好知識。

          那是1989年的第一場雪,比1988年來的更早一些,伯納斯·李(Tim Berners-Lee)以超人的智慧和消耗了前額無數濃密的頭發為代價發明了World Wide Web,沒有他就沒有我們今天互聯網相關的工作,也就沒有了這個專欄教程,請允許我代表廣大前端致以崇高的敬意。我們先一睹大神的風采。

          對互聯網之父,我只想對他說一句話,有一款洗發水增發效果挺好的,我一直用,你要不要試試?

          互聯網誕生了以后,最初的網頁僅僅是純文本,但是隨著互聯網的發展,大家意識到web的原始版本根本就沒有提供一種裝飾網頁的方法。這就好比一個嬰兒不會穿著衣服出生一樣,孩子大了,總不能裸奔吧?這個時候兩個大神提供了解決方案Pei Yaun Wei和Andreesen。

          Pei Yaun Wei說,這個好辦,我們可以給孩子穿上紙尿褲。

          Pei-Yuan Wei在1991年創建圖形瀏覽器 ViolaWWW ,他整合了自己提出的樣式語言到自己開發的瀏覽器中,還期望自己的樣式語法最終能成為web關于樣式的官方標準。雖然這個目標并未達到,但是他提出的樣式語法確實為其它的一些樣式語法提供了一些靈感。

          Andreesen說,那玩意得換多麻煩,我給孩子畫一身衣服吧,當然你懂的,最后Pei Yaun Wei的方案被采用了,但是我們還是看看Andreessen畫出來的情況有多亂。

          與此同時,Andreessen 在他開發的網景瀏覽器中進行了不同的嘗試。他并沒有創建一種分離式的標記語言,而是采取拓展HTML標簽的方法來包含非標準化的HTML標簽已達到裝飾網頁的目的。不幸的是,沒過多久,網頁就失去了所有的語義化并看起來像下面這樣混亂:

          <MULTICOL COLS="3" GUTTER="25">
           <P><FONT SIZE="4" COLOR="RED">This would be some font broken up into columns</FONT></P></MULTICOL>
          

          最終被大家采納的語言是由Hakon Wium 在 1994年 10月提出的樣式語法。它被稱為樣式層疊表,簡稱CSS,但是直到1996年的時候,CSS才演變成我們熟悉的樣子。

          html { margin-left: 2cm; font-family: "Times", serif;
          }h1 { font-size: 24px;
          }
          

          然后在1998年5月W3C發表了CSS2,緊接著一個讓我們深惡痛覺的瀏覽器誕生了!對沒錯,就是你深惡痛絕的那個萬能的IE6,2001年微軟發布了IE6,不過搞笑的是,IE6最初的出現確實很大程度推動了CSS發展。那時候的網頁已經變成跟現在很接近了。

          按照常理你肯定會想,后面我就知道了,你不用說了,然后就是CSS3.0了。好吧,如果是我,我也這樣想,但是國際友人的腦回路可能跟我們不一樣,事實上,CSS3早于1999年已經開始制訂,直到2011年6月7日,CSS 3 Color Module終于發布為W3C Recommendation。這個故事告訴我們兩件事:

          1.w3c這個組織活的真夠長,甚至比很多讀者年齡都大。

          2.不是CSS正式版發布了你才放心使用,如果等到那個時候使用,你的項目可能未曾綻放就枯萎了。

          細心的讀者可能會問了,CSS3正式版什么時候發布啊?另外CSS4.0什么時候發布?

          好吧,我只能告訴你隨緣吧……而且沒有CSS4.0了,也不會有CSS5.0了。

          來我們再看看國際友人的腦回路:

          簡單地說,就是從CSS3開始,CSS規范就被拆成眾多模塊(module)單獨進行升級,或者將新需求作為一個新模塊來立項并進行標準化。因此今后不會再有CSS4、CSS5這種所謂大版本號的變更,有的只是CSS某個模塊級別的躍遷。

          按照CSS工作組的說法,CSS歷史上并沒有版本的概念,有的只是“級別”(level)的概念。比如,CSS3其實是CSS Level 3,CSS2是CSS Level 2,而CSS Level 1當然就是CSS1。每個級別都以上一個級別為基礎。

          大家可能說這個命名好亂啊,這事兒我只想跟你說,你就把CSS工作組當成你女朋友就好了,她開心就好,她說的都是對的,她說啥就是啥……

          至于我們,會用就好了。

          CSS出現的好處就是讓結構和表現分離,可以更靈活的修飾網頁,學習也很簡單。這里我更想說說它的不足。

          1.CSS只有一個全局的命名空間,所以是無法避免出現選擇器沖突的。

          2.模塊化做的不夠好,所以造成嵌套和覆蓋混亂,容易產生一大堆亂糟糟的樣式。

          所以現在CSS也在向“模塊化、JS化發展”

          不過客觀地說,CSS的出現確實是互聯網里程碑式的進步。

          CSS其實就做了兩件事:

          1.如何布局

          2.元素怎么表現

          說直白一點就是兩件事,一個房子是蓋成兩室一廳還是三室兩廳,另一件事是精裝修。

          這里大家就會看到如果一個房子180平米隔成1個10平米的主臥170平米的廁所,你再怎么精裝修也不會是一個宜居的房間。所以布局在CSS中是極其重要的。與CSS發展簡史類似,CSS布局也經歷了一代又一代的迭代,才成為當前的樣子。

          接下來我們就說說CSS布局簡史。

          2.CSS布局簡史

          初代table布局

          在1997年的時候,David Siegel 改變了web,他自己研究出了一項網頁布局技術,利用html中的table元素和gif圖片縫合在一起,創造了表格布局技術,之后他就猶如一頭猛獸泛濫起來。

          優點:布局容易、快捷、兼容性好

          缺點:改動不便,需要重新調整,工作量大

          由于互聯網網站越來越復雜,內容和業務更新頻繁,所以table布局是完全不能勝任的,以至于table布局的發明人都說:

          “我把炸醬和面倒在了一起,并且沒法分開它。”

          不過這個真不是我杜撰出來的,原文:

          David Siegel:“有人說我毀掉了Web,我回答他們,的確如此。我毀掉了Web是因為我把巧克力和花生醬混合在一起卻再也不能把它們分開。我犯下了把結構跟表現混合在一起的錯誤。”

          然后第二代布局技術登場了,

          CSS+div布局

          CSS+div布局總結起來有三大優點,

          1.省時,學習容易,寫代碼也很容易,很快,效率高

          2.省事,如果業務邏輯變了,改起來特別方便快捷

          3.省錢,代碼量少,省帶寬,適合seo

          基于這三年不難看出CSS+div布局人畜無害,人見人愛,也就不難解釋為什么被廣泛地使用成為目前主流的布局技術了。當然了他也有缺點:

          1.需要考慮平臺兼容性,對制作人員的技能要求較高。

          2.在移動端布局顯得有些力不從心,如未知寬高float內部元素居中、垂直水平布局、響應式布局等方面略顯繁瑣。

          基于此,第三代布局技術應運而生。

          Flex布局

          優點:

          1.CSS3的布局方式,可以在不使用其他框架的情況下,簡便、完整、響應式地實現各種頁面布局 2.移動端布局簡直太友好

          缺點:

          兼容性較差,IE瀏覽器版本在9.0以上,基本要10.0 對于其他瀏覽器,要求兼容性寫法

          Flex布局日漸成為移動端主流布局技術,但是它是單一維度的布局,這個我會在專欄后面講到,有時候也會捉襟見肘,所以目前出現了第四代的布局技術:

          grid布局

          因為目前大部分瀏覽器并不支持這種技術,但是它代表了網絡發展,這里大家保持關注就好,這里我重點說下它為什么可以稱為第四代網絡布局技術。首先一個觀點大家先記住:

          它并不會取代第三代的布局技術,而是顛覆和突破。就好像Flex遠比div+CSS布局更方便,但是div+CSS依然有用武之地。

          我們說下它的突破之處:

          1.flex對標的是float,本質上還是一維布局,這就跟別人開著夏利,你開奔馳都是地面上跑沒啥本質區別一樣。但是grid升維了,grid是飛機,在地面馬路這條線一維之上讓人能夠思考高度這個維度,以前是汽車一維交通工具(你只能在水平方向一個方向開),飛機是二維(能俯沖了(橫向、縱向同時)),所以grid可以說是拓寬了CSS布局的維度。不排除將來會有三維布局的出現。到時候CSS不僅僅能控制橫向布局,縱向布局,還可以深度布局(這個要依賴于三維展示的出現,如VR,AR三維立體的展示設備出現)。

          2.grid布局里面采用了“可視化布局(template部分,所見即所得)”,這個是顛覆了傳統的,寫一句代碼刷一下瀏覽器這樣的開發方式,不排除以后會出現代碼即效果的開發模式。比如你在一個設備上畫一個區域,然后畫輪播圖。

          這種方式類似于vc++控件方式,但是更智能,也更友好。誰說不可能呢?大家不要忘了grid布局的來源是早就廢棄的table布局。說到這里我多說一句搞笑的微軟,frontpage沒火,dreamwaver火了,最早提出“canvas”概念的 VML沒火,最后html5的canvas火了,連CSS3網格布局也是由微軟創建的一個模塊 ,最后火起來居然沒人認識它。心疼微軟一秒鐘。

          說到這里大家對CSS簡史和布局也有所了解了,我們總結下,通過本文你應該學到:

          (1)CSS的發展歷史。

          (2)熟知布局的發展歷史,以便對未來布局技術的發展有一個客觀的判斷,來選擇是否學習。

          通過本文的學習大家已經對CSS相關基礎知識有所了解,接下來我們就開始真正的進入技術的學習,大家是不是迫不及待了呢?


          主站蜘蛛池模板: 亚洲AV无码一区二区三区牛牛| 亚洲综合一区二区精品导航| 中文字幕乱码亚洲精品一区| 麻豆视传媒一区二区三区| 动漫精品专区一区二区三区不卡| 亚洲色一区二区三区四区| 无码成人一区二区| 精品一区二区三区四区在线播放| 久久精品无码一区二区三区| 精品视频一区二区三区免费| 中文字幕精品无码一区二区| 国产传媒一区二区三区呀| 本免费AV无码专区一区| 久久免费区一区二区三波多野| 中文字幕一区二区三区在线观看 | 视频精品一区二区三区| 国产精品一区二区三区99| 国内国外日产一区二区| 国产一区二区三区免费| 精品午夜福利无人区乱码一区| 无码av不卡一区二区三区| 久久久精品人妻一区二区三区四| 波多野结衣AV一区二区三区中文| 波多野结衣一区二区三区88| 亚洲综合av永久无码精品一区二区| 亚洲av日韩综合一区二区三区| 国产激情无码一区二区三区| 97av麻豆蜜桃一区二区| 亚洲午夜日韩高清一区| 亚洲av无码一区二区三区天堂| 国产亚洲自拍一区| 日本免费精品一区二区三区| 国产精品一区二区久久精品| 天天视频一区二区三区| 无码一区二区三区视频| 一区二区三区在线免费观看视频| 亚洲av无码一区二区三区在线播放| 无码人妻精品一区二区三区东京热 | 武侠古典一区二区三区中文| 亚洲色精品VR一区区三区| 另类一区二区三区|