Vue原理概述及Object.defineProperty
阿新 • • 發佈:2021-01-16
技術標籤:Vue
主要考察什麼
- 考察重點, 而不是考察細節,二八原則
- 和使用相關的原理, 例如vdom, 模板渲染
- 整體流程是否全面? 熱門技術是否有深度?
原理
- 元件化
- 響應式
- vdom和diff
- 模板編譯
- 渲染過程(開放題目, 全面)
- 前端路由
元件化
MVVM模型 資料驅動檢視
- 不再操作dom, 只需要去更改資料, 框架會自動更改檢視
如何理解MVVM
元件化, 資料驅動檢視
view <-> viewModel <-> Model
響應式
- 元件data的資料一旦變化, 檢視就會立刻更新
如何知道data變化?
- 核心API: Object.defineProperty
- 如何實現響應式, 監聽物件/監聽陣列
- Object.defineProperty的缺點, Vue3.0啟用Proxy
Proxy有相容性問題, 且無法polyfill
Object.defineProperty的基本用法
const data = {}
const name = 'zhangsan'
//核心API
Object.defineProperty(data,"name",{
get: fucntion(){
console.log('get')
return name
},
set: function(newVal){
console. log('set')
name = newVal
}
})
console.log(data.name) //get zhangsan
data.name = 'lisi' //set
Object.defineProperty實現響應式
監聽物件, 監聽資料, 深度監聽
function defineReactive(target,key,value){
//深度監聽
observer(value)
//程式碼類似上述核心API
Object.defineProperty(target,key,{
get: fucntion (){
console.log('get')
return value
},
set: function(newVal){
console.log('set')
if(newVal !== value){
//設定新值, 深度監聽
observer(newVal)
value = newVal
//觸發檢視更新
updateView()
}
}
})
}
function obeserver(target){
if(typeof target !== 'object' || target === null){
//不是物件或陣列
return target
}
//重新定義各個屬性
for(let key in target){
defineReactive(target, key, target[key])
}
}
//外層
const data = {
score : 90,
name: 'zhangsan',
info:{
age:20,
sex:'female'
}
}
observer(data)
//還有一種情況
data.score = {math:90}
//對新值再次更新
data.score.math = 80
//這種情況下, 就需要新值也要被監聽起來, 更改時才能觸發檢視更新
缺點
- 深度監聽, 需要遞迴到底, 一次性計算量大
是否可以不一次性計算, 需要用到的時候再進行計算, 分多次遞迴完
Object.defineProperty
無法監聽新增/刪除屬性, 所以需要Vue.set, Vue.delete 做這件事情
data.x = 'xxx'
delete data.info
- 無法監聽陣列的變化, 需要特殊處理
vue中如何監聽陣列的變化
//重新定義陣列原型
const oldArrayProperty = Array.prototype
//建立新物件, 物件原型指向oldArrayProperty
const arrProto = Object.create(oldArrayProperty)
//重新定義陣列的幾個方法, 可以寫多個
['push','pop','shift','unshift','splice'].forEach(methodName => {
arrProto[methodName] = function(){
//觸發檢視更新
updateView()
//繼續呼叫使用原型中的該方法本身
oldArrayProperty[methodName].call(this,...arguments)
//= Array.prototype[methodName].call(this,...arguments)
}
})
在上一節observer()
函式中, 對陣列進行特殊判斷
function obeserver(target){
if(typeof target !== 'object' || target === null){
//不是物件或陣列
return target
}
//不能這樣直接修改Array.prototype, 會汙染全域性的Array原型
//Array.prototype.push = function(){
// updateView()
// ...
//}
if(Array.isArray(target)){
//將原型屬性指向arrProto
//那麼執行那幾個函式時就會進行檢視更新
target.__proto__ = arrProto
}
//重新定義各個屬性
for(let key in target){
defineReactive(target, key, target[key])
}
}