# 1.JS 數字精讀丟失問題
參考鏈接:[https://www.cnblogs.com/snandy/p/4943138.html](https://www.cnblogs.com/snandy/p/4943138.html)
## 常見的數字精讀丟失的情況
1.兩個浮點數相加
```js
console.log(0.1 + 0.2 !== 0.3) // true
console.log(0.1 + 0.2) // 0.30000000000000004
```
2.大整數運算(多少位?)
```js
console.log(9999999999999999 === 10000000000000001) // true
var x = 9007199254740992
console.log(x + 1 === x) // true
```
3.toFixed() 沒有四舍五入,此外 toFixed 還有一些兼容性問題
```js
console.log(1.335.toFixed(2)) // 1.33
```
## 原因
JS 遵循[IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point)規范,采用雙精度存儲(double precision),占用 64 bit。如圖

- 1位用來表示符號位
- 11位用來表示指數
- 52位表示尾數
浮點數,比如
```js
0.1 >> 0.0001 1001 1001 1001…(1001無限循環)
0.2 >> 0.0011 0011 0011 0011…(0011無限循環)
```
此時只能模仿十進制進行四舍五入了,但是二進制只有 0 和 1 兩個,于是變為 0 舍 1 入。這即是計算機中部分浮點數運算時出現誤差,丟失精度的根本原因。
大整數的精度丟失和浮點數本質上是一樣的,尾數位最大是 52 位,因此 JS 中能精準表示的最大整數是 Math.pow(2, 53),十進制即 9007199254740992。
大于 9007199254740992 的可能會丟失精度
```js
9007199254740992 >> 10000000000000...000 // 共計 53 個 0
9007199254740992 + 1 >> 10000000000000...001 // 中間 52 個 0
9007199254740992 + 2 >> 10000000000000...010 // 中間 51 個 0
```
## 解決方案
對于整數,前端出現問題的幾率可能比較低,畢竟很少有業務需要需要用到超大整數,只要運算結果不超過 Math.pow(2, 53) 就不會丟失精度。(如果遇到一般會用字符串來替代?)
對于小數,前端出現問題的幾率還是很多的,尤其在一些電商網站涉及到金額等數據。解決方式:把小數放到位整數(乘倍數),再縮小回原來倍數(除倍數)
```js
// 0.1 + 0.2
(0.1*10 + 0.2*10) / 10 == 0.3 // true
```
對于 toFixed 方法出現的問題
```js
/**
*
* @param {*} num 需要轉化的數值
* @param {*} s 保留到小數點后第幾位
*/
function toFixed (num, s) {
let times = Math.pow(10, s)
let des = num * times + 0.5
des = parseInt(des, 10) / times
return des + ''
}
console.log(toFixed(1.335, 2)) // 1.34
```
>TODO:這里的解決方案感覺不是很好,有空再找找...
# 2.幾個細節題
```js
// this 指向
var obj = {
name: 'foo',
fun1: function () {
console.log(this.name)
},
fun2: () => {
console.log(this.name)
}
}
var fun3 = obj.fun1
fun3()
obj.fun1()
obj.fun2()
```
```js
// 事件循環 - resolve 之后是否會繼續往下執行?
setTimeout(function () {
console.log('a')
})
var p = new Promise(function (resolve, reject) {
console.log('b')
resolve()
console.log('c')
})
p.then(function () {
console.log('d')
})
console.log('e')
```
```js
// 原型鏈 構造函數的 __proto__ 指向什么呢?
Function.prototype.a = 1
Object.prototype.a = 2
Object.a = ?
```
# 3.模擬實現 lodash 中的 \_.get() 函數
模擬實現 lodash 中的 \_.get() 函數,實現如下傳入參數取值效果
```js
function get() {
// 請補全函數參數和實現邏輯
}
const obj = {
selector: { to: { toutiao: 'FE coder' } },
target: [1, 2, { name: 'byted' }]
};
// 運行代碼
get(obj, 'selector.to.toutiao', 'target[0]', 'target[2].name')
// 輸出結果:// ['FE coder', 1, 'byted']
```
勉強實現了
```js
function get (obj, ...args) {
const res = [] // 存儲返回結果
const params = args
params.forEach(item => { // 'selector.to.toutiao' , 'target[0]', 'target[2].name'
let splitItem = item.split('.') // -> ['selector', 'to', 'toutiao'], ['target[0]'], ['target[2], 'name']
let temp = null
splitItem.forEach(value => {
let index = value.indexOf('[') // case of 'target[0]'
if (index !== -1) {
let num = parseInt(value.substring(index + 1)) // 數組下標 Number 類型
let attr = value.substring(0, index)
temp = temp === null ? obj[attr][num] : temp[attr][num]
} else {
temp = temp === null ? obj[value] : temp[value] // obj.selector.to.toutiao
}
})
res.push(temp)
})
return res
}
console.log(get(obj, 'selector.to.toutiao', 'target[0]', 'target[2].name'))
```
# 4.找出頁面出現最多的標簽
你知道 `document.getElementsByTagName('*')`的用法嗎?
```js
// 獲取元素列表,以鍵值對的形式存儲為一個對象
function getElements () {
// 如果把特殊字符串 "*" 傳遞給 getElementsByTagName() 方法
// 它將返回文檔中所有元素的列表,元素排列的順序就是它們在文檔中的順序。
// 返回一個 HTMLCollection - 類數組對象
const nodes = document.getElementsByTagName('*')
const tagsMap = {}
for (let i = 0, len = nodes.length; i < len; i++) {
let tagName = nodes[i].tagName
if (!tagsMap[tagName]) {
tagsMap[tagName] = 1
} else {
tagsMap[tagName] ++
}
}
return tagsMap
}
// n 為要選取的標簽個數 - 即出現次數前 n 的標簽名
// 將上面的方法獲取的對象的鍵值對取出組成數組,按出現次數排序
function sortElements (obj, n) {
const arr = []
const res = []
for (let key of Object.keys(obj)) {
arr.push({ tagName: key, count: obj[key] })
}
// 冒泡
for (let i = arr.length - 1; i > 0; i--) {
for (let j = 0; j < i; j++) {
if (arr[j].count < arr[j + 1].count) { // 升序
swap(arr, j, j + 1)
}
}
}
for (let i = 0; i < n; i++) {
res.push(arr[i].tagName)
}
return res
}
function swap (arr, index1, index2) {
let temp = arr[index1]
arr[index1] = arr[index2]
arr[index2] = temp
}
let res = sortElements(getElements(), 2)
console.log(res)
```
# 5.細節問題
以下代碼的執行結果是什么?
```js
function func() {
var a = b = 1;
}
func();
console.log(a);
console.log(b);
```
答案:error,1
解析:b 沒有 var 為全局變量,var a = b 局部變量外部訪問不到
# 6.fetch 本身不支持 timeout,能否對其進行封裝使其支持 timeout?
參考:[https://imweb.io/topic/57c6ea35808fd2fb204eef63](https://imweb.io/topic/57c6ea35808fd2fb204eef63)
```js
/**
* 包裝 fetch 方法,使其支持 timeout
* @param {Promise} fetch_promise fetch 請求
* @param {Numebr} timeout 超時時間設置
*/
function _fetch (fetch_promise, timeout) {
var abort_fn = null
// 這是一個可以被 reject 的 promise
var abort_promise = new Promise(function (resolve, reject) {
abort_fn = function () {
reject('abort promise')
}
})
// 這里使用 Promise.race, 以最快 resolve 或 reject 的結果來傳入后續綁定的回調
var abortable_promise = Promise.race([
fetch_promise,
abort_promise
])
setTimeout(() => {
abort_fn()
}, timeout)
return abortable_promise
}
// usage
_fetch(fetch('http://test.com'), 2000)
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
```
- 序言 & 更新日志
- H5
- Canvas
- 序言
- Part1-直線、矩形、多邊形
- Part2-曲線圖形
- Part3-線條操作
- Part4-文本操作
- Part5-圖像操作
- Part6-變形操作
- Part7-像素操作
- Part8-漸變與陰影
- Part9-路徑與狀態
- Part10-物理動畫
- Part11-邊界檢測
- Part12-碰撞檢測
- Part13-用戶交互
- Part14-高級動畫
- CSS
- SCSS
- codePen
- 速查表
- 面試題
- 《CSS Secrets》
- SVG
- 移動端適配
- 濾鏡(filter)的使用
- JS
- 基礎概念
- 作用域、作用域鏈、閉包
- this
- 原型與繼承
- 數組、字符串、Map、Set方法整理
- 垃圾回收機制
- DOM
- BOM
- 事件循環
- 嚴格模式
- 正則表達式
- ES6部分
- 設計模式
- AJAX
- 模塊化
- 讀冴羽博客筆記
- 第一部分總結-深入JS系列
- 第二部分總結-專題系列
- 第三部分總結-ES6系列
- 網絡請求中的數據類型
- 事件
- 表單
- 函數式編程
- Tips
- JS-Coding
- Framework
- Vue
- 書寫規范
- 基礎
- vue-router & vuex
- 深入淺出 Vue
- 響應式原理及其他
- new Vue 發生了什么
- 組件化
- 編譯流程
- Vue Router
- Vuex
- 前端路由的簡單實現
- React
- 基礎
- 書寫規范
- Redux & react-router
- immutable.js
- CSS 管理
- React 16新特性-Fiber 與 Hook
- 《深入淺出React和Redux》筆記
- 前半部分
- 后半部分
- react-transition-group
- Vue 與 React 的對比
- 工程化與架構
- Hybird
- React Native
- 新手上路
- 內置組件
- 常用插件
- 問題記錄
- Echarts
- 基礎
- Electron
- 序言
- 配置 Electron 開發環境 & 基礎概念
- React + TypeScript 仿 Antd
- TypeScript 基礎
- React + ts
- 樣式設計
- 組件測試
- 圖標解決方案
- Storybook 的使用
- Input 組件
- 在線 mock server
- 打包與發布
- Algorithm
- 排序算法及常見問題
- 劍指 offer
- 動態規劃
- DataStruct
- 概述
- 樹
- 鏈表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 課程實戰記錄
- 服務器
- 操作系統基礎知識
- Linux
- Nginx
- redis
- node.js
- 基礎及原生模塊
- express框架
- node.js操作數據庫
- 《深入淺出 node.js》筆記
- 前半部分
- 后半部分
- 數據庫
- SQL
- 面試題收集
- 智力題
- 面試題精選1
- 面試題精選2
- 問答篇
- 2025面試題收集
- Other
- markdown 書寫
- Git
- LaTex 常用命令
- Bugs