[TOC]
## vue 的 computed / watch 的區別
從其用途來看:
計算屬性用于 HTML 模板中,用于代替模板表達式`{{ }}}`中的一些復雜邏輯;
偵聽屬性是一種通用的用于觀察和響應 Vue 實例上的數據變動的方式;
其書寫方式如下:
```js
var vm = new Vue({
el: '#example',
data: {
message: 'Hello',
firstName: 'Foo',
},
computed: {
// 計算屬性的 getter
reversedMessage: function () {
// `this` 指向 vm 實例
return this.message.split('').reverse().join('')
}
},
watch: {
// 監聽的屬性和其發生變化后觸發的回調
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
}
}
})
```
就應用場景而言,計算屬性適合用在模板渲染中,某個值是依賴了其它的響應式對象甚至是計算屬性計算而來;而偵聽屬性適用于觀測某個值的變化去完成一段復雜的業務邏輯。
從其特性來看:
這里主要考慮頁面重新渲染時兩者的區別,當頁面重新渲染(不是刷新)的時候,計算屬性不會變化,直接讀取緩存使用,只有在相關依賴發生改變時才會重新求值。而偵聽屬性在頁面重新渲染時即使值不變化也會執行。
>什么才算頁面重新渲染?
[從源碼的角度來分析](https://ustbhuangyi.github.io/vue-analysis/prepare/flow.html):
......好吧我講不出來讓面試官給我講講吧
## webpack 相比 rollup 有哪些優點、缺點?
目前 Vue、React 等一些有名的 JS 庫都是采用 rollup 來進行打包的,比較流行的說法是 rollup 更適合構建 JavaScript 庫而 webpack 更適合構建前端應用。
- 如果你確實需要代碼分割特性,或者你有很多靜態資源需要處理,再或者你構建的項目需要引入很多 CommonJS 模塊的依賴,那么 Webpack 是個很不錯的選擇。
- 如果你的代碼是基于 ES2015 模塊,而且希望你寫的代碼能夠被其他人直接使用,你需要的打包工具可能是 Rollup。
回到這個題目:webpack 相比 rollup 有以下的優點
- 支持熱模塊更新
- 代碼分割功能強大,利于處理 CommonJS 模塊的依賴
- 擴展性強、插件機制完善,利于處理多種不同格式的靜態資源
有以下缺點:
- 構建速度較慢
- 配置較復雜
關于為何 rollup 構建速度更快可以參考其 [中文文檔](https://www.rollupjs.com/guide/zh#tree-shaking)
## 為什么實際應用中 Last-Modified 和 etag 都會使用到?
主要是因為如果文件內容被修改了但是實際上并沒有變化,比如刪掉一個字符 a 又填上去,該文件的 Last-Modified 會發生變化,但是 Etag 不會變。
下面貼兩段介紹吧:
? Last-Modified / If-Modified-Since:`Last-Modified`表示本地文件最后修改日期,`If-Modified-Since`會將上次從服務器獲取的`Last-Modified`的值發送給服務器,詢問服務器在該日期后資源是否有更新,有更新的話就會將新的資源發送回來。
但是如果(服務器)在本地打開緩存文件(或者刪了個字符 a 后又填上去),就會造成`Last-Modified`被修改,所以在 HTTP / 1.1 出現了`ETag`。
? Etag / If-None-Match:`ETag`類似于文件指紋,`If-None-Match`會將當前`ETag`發送給服務器,詢問該資源`ETag`是否變動,有變動的話就將新的資源發送回來。并且`ETag`優先級比`Last-Modified`高。
由于 etag 要使用少數的字符表示一個不定大小的文件(如 Etag: "58c4e2a1-f7"),所以 etag 是有重合的風險的,如果網站的信息特別重要,連很小的概率如百萬分之一都不允許,那么就不要使用 etag 了。使用 etag 的代價是增加了服務器的計算負擔,特別是當文件比較大時。
## node 的基本特點?異步 I/O 的優勢?如何讀取大文件?
- 基本特點
- 異步 I/O:Node 在底層構建了很多異步 I/O 的 API,從文件讀取到網絡請求,極大地提升了程序性能
- 事件與回調函數:配合異步 I/O,將事件點暴露給業務邏輯。這種事件的編程方式具有輕量級、松耦合、只關注事務點等優勢
- 單線程:單線程的最大好處是不用像多線程編程那樣處處在意狀態的同步問題,沒有死鎖的存在,也沒有線程上下文交換所帶來的性能上的開銷。但是它也有以下弱點(child process 模塊出現后都得到了解決或緩解):
- 無法利用多核 CPU
- 錯誤會引起整個應用退出,應用的健壯性值得考驗
- 大量計算占用 CPU 導致無法繼續調用異步 I/O
- 跨平臺:借助 libuv 實現跨平臺運行
- 異步 I/O 的優勢:Node 面向網絡并且擅長并行 I/O,能夠有效地組織起更多的硬件資源,在 I/O 密集型場景表現還是不錯的
- 利用 stream 模塊分批次地讀取大文件
```js
// 復制文件
const fs = require('fs')
const path = require('path')
const fileName1 = path.resolve(__dirname, 'data.txt')
const fileName2 = path.resolve(__dirname, 'data-bak.txt')
const readStream = fs.createReadStream(fileName1)
const writeStream = fs.createWriteStream(fileName2)
readStream.pipe(writeStream) // 可讀流調用 pipe 方法讓數據通過管道從可讀流流入可寫流
readStream.on('data', chunk => {
console.log(chunk)
console.log(chunk.toString()) // 可以看到文件是分批次地讀取的
})
readStream.on('end', () => {
console.log('copy done')
})
```
## 如果動態給 Vue 實例添加屬性,如何監聽到新增屬性的變化?
使用 Vue 提供的 API `Vue.set( target, propertyName/index, value )`
向響應式對象中添加一個屬性,并確保這個新屬性同樣是響應式的,且觸發視圖更新。它必須用于向響應式對象上添加新屬性,因為 Vue 無法探測普通的新增屬性 (比如`this.myObject.newProperty = 'hi'`)
注意這里的響應式對象(target)是 data 選項中已存在的對象。
可以參考這篇文章:[https://www.jianshu.com/p/71b1807b1815](https://www.jianshu.com/p/71b1807b1815)
## 列舉幾個在 web 中實現長連接的技術方案
什么是長連接?長連接就是讓 HTTP 協議所需要使用的 TCP 連接保持不斷開的狀態,因為對每個請求都頻繁地建立和斷開 TCP 連接會造成很大的時間開銷。
- 響應頭 keep-alive:自 HTTP/1.1 起,默認使用長連接,即自動添加該響應頭
- 輪詢
- websocket
[https://www.cnblogs.com/huchong/p/8595644.html](https://www.cnblogs.com/huchong/p/8595644.html)
## 不同子域如何共享一段 js 腳本?
`a.test.com`和`b.test.com`應該算不同子域吧?這個問題考察的是跨域技巧嗎?只需要給頁面添加`document.domain = 'test.com'`表示二級域名都相同就可以實現跨域。
## vuex 的設計思想?與 redux 的區別?
在 Vuex 中,store 被直接注入到了所有的組件實例中,因此可以比較靈活的使用:
* 使用 dispatch 和 commit 提交更新
* 通過 mapState 或者直接通過 this.$store 來讀取數據
在 Redux 中,我們每一個組件都需要顯式地用 connect 把需要的 props 和 dispatch 連接起來。
從實現原理上來說,最大的區別是兩點:
* Redux 使用的是不可變數據,而 Vuex 的數據是可變的。Redux 每次都是用新的 state 替換舊的 state,而 Vuex 是直接修改
* Redux 在檢測數據變化的時候,是通過 diff 的方式比較差異的,而 Vuex 其實和 Vue 的原理一樣,是通過 getter/setter 來比較的(如果看 Vuex 源碼會知道,其實他內部直接創建一個 Vue 實例用來跟蹤數據變化)
而這兩點的區別,其實也是因為 React 和 Vue 的設計理念上的區別。React 更偏向于構建穩定大型的應用,非常的科班化。相比之下,Vue 更偏向于簡單迅速的解決問題,更靈活,不那么嚴格遵循條條框框。因此也會給人一種大型項目用 React,小型項目用 Vue 的感覺。(這是別人的總結哦:[https://juejin.im/post/5b8b56e3f265da434c1f5f76#heading-0](https://juejin.im/post/5b8b56e3f265da434c1f5f76#heading-0))
## 設計一個秒殺系統需要注意什么問題?
也可以這么說:假設一萬人搶一個東西,前端需要注意些什么?
其實這個問題更適合完全做后端的同學來答...
因為我也沒做過秒殺系統所以就 copy 以下別人的回答吧:[https://juejin.im/post/595b5a8a5188250da1276a95](https://juejin.im/post/595b5a8a5188250da1276a95)
前端可能的狀態:
- 秒殺開始前,秒殺按鈕灰掉為“未開始”,不可點擊。
- 秒殺進行中,秒殺按鈕可以點擊下單。
- 秒殺結束后,秒殺按鈕灰掉為“已結束”,不可點擊。
具體的需求:
1、秒殺產品的介紹,詳情,參數等等,全部靜態化,切勿通過后臺 API 查詢更新,減輕后端的壓力。
2、用戶點擊“下單”后,按鈕置灰,禁止用戶重復提交請求,限制用戶在 60 秒之內只能提交一次請求。
3、下單的 URL 在活動開始前不可露出或者生效,否則容易被使用工具繞過瀏覽器提前下單。導致活動還未開始,已經開始下單這個大黑洞。正確的做法是活動開始前,通過更新 JS 文件露出下單的 URL(這個怎么做到?)。
4、下單過程中,涉及到訂單參數的修改全部關掉,比如,購買的金額,產品的份額等等,降低訂單服務的壓力。
## vue 3.0 使用 proxy 重構的原因?
參考鏈接:[https://segmentfault.com/a/1190000015483195](https://segmentfault.com/a/1190000015483195)
首先羅列`Object.defineProperty()`的缺點:
1、`Object.defineProperty()`不會監測到數組引用不變的操作(比如`push/pop`等);
2、`Object.defineProperty()`只能監測到對象的屬性的改變, 即如果有深度嵌套的對象則需要再次給之綁定`Object.defineProperty()`;
關于`Proxy`的優點
1、可以劫持數組的改變;
2、`defineProperty`是對屬性的劫持,`Proxy`是對對象的劫持;
為了加深理解,我們來舉幾個例子:
先來看看為什么說`Object.defineProperty()`不能監測到數組變化:
```js
const data = {
list: []
}
Object.keys(data).forEach(function (key) {
let value = data[key]
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get () {
return value
},
set (newValue) {
console.log('set value')
value = newValue
return true
}
})
})
// 所謂對數組的監控,即能檢測到數組元素的增加和刪除
data.list.push(1) // nothing happen
console.log(data.list)
data.list = [2, 3] // set value
console.log(data.list)
```
當監控數組數據對象的時候,實質上就是監控數組的地址,地址不變也就不會被監測到,所以我們向 list 里 push 元素的時候并沒有觸發打印;當我們直接替換 list 對象的時候就觸發了打印。所以這就是`Object.defineProperty`在數組監控方面的不足。
我們總是說 Vue 使用 hack 方法彌補了這個缺陷,那么看下其大致思路:
```js
let arrayMethod = Object.create(Array.prototype);
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) {
Object.defineProperty(arrayMethod, method, {
enumerable: true,
configurable: true,
value: function () {
let args = [...arguments]
Array.prototype[method].apply(this, args);
console.log(`operation: ${method}`)
dep.notify();
}
})
});
[Array Object].__proto__ = arrayMethod;
```
其核心思想就是`覆寫`數組對象中的方法,在調用數組方法的同時能觸發回調。同時這樣做的好處是,僅僅是數據中的數組對象的原型被修改掉了,并不會影響到全局的數組對象。
最后用 proxy 來試下其是否能檢測到數組元素變化:
```js
const data = {
list: [1, 2, 3, 4]
}
const proxyArr = new Proxy (data.list, {
get: function (target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set: function (target, key, value, receiver) {
console.log(target, key, value, receiver)
return Reflect.set(target, key, value, receiver)
}
})
proxyArr.push(2)
// [ 1, 2, 3, 4 ] '4' 2 [ 1, 2, 3, 4 ]
// [ 1, 2, 3, 4, 2 ] 'length' 5 [ 1, 2, 3, 4, 2 ]
proxyArr.shift()
/*
[ 1, 2, 3, 4 ] '4' 2 [ 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 2 ] 'length' 5 [ 1, 2, 3, 4, 2 ]
[ 1, 2, 3, 4, 2 ] '0' 2 [ 1, 2, 3, 4, 2 ]
[ 2, 2, 3, 4, 2 ] '1' 3 [ 2, 2, 3, 4, 2 ]
[ 2, 3, 3, 4, 2 ] '2' 4 [ 2, 3, 3, 4, 2 ]
[ 2, 3, 4, 4, 2 ] '3' 2 [ 2, 3, 4, 4, 2 ]
[ 2, 3, 4, 2, <1 empty item> ] 'length' 4 [ 2, 3, 4, 2, <1 empty item> ]
*/
```
可以看到確實可以監測到數組元素變化。
## 頁面出現長時間白屏,怎么辦?
[https://juejin.im/post/5bee7dd4e51d451f5b54cbb4](https://juejin.im/post/5bee7dd4e51d451f5b54cbb4)
## babel 的轉譯原理?
詳細的可以閱讀這篇文章:[JavaScript 深入理解 Babel 原理及其使用](https://www.jianshu.com/p/e9b94b2d52e2)
babel 是一個轉譯器,相對于編譯器 compiler,叫轉譯器 transpiler 更準確,因為它只是把同種語言的高版本規則翻譯成低版本規則,而不像編譯器那樣,輸出的是另一種更低級的語言代碼。
但是和編譯器類似,babel 的轉譯過程也分為三個階段:`parsing`、`transforming`、`generating`,以 ES6 代碼轉譯為 ES5 代碼為例,babel 轉譯的具體過程如下:
>[success]ES6 代碼輸入 → babylon 進行解析 → 得到 AST → plugin 用 babel-traverse 對 AST 樹進行遍歷轉譯 → 得到新的 AST 樹 → 用 babel-generator 通過 AST 樹生成 ES5 代碼
此外,還要注意很重要的一點就是,babel 只是轉譯新標準引入的語法,比如 ES6 的箭頭函數轉譯成 ES5 的函數;而新標準引入的新的原生對象,部分原生對象新增的原型方法,新增的 API 等(如 Proxy、Set 等),這些 babel 是不會轉譯的。需要用戶自行引入 polyfill 來解決。
- 序言 & 更新日志
- 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