Vue檢測(cè)數(shù)據(jù)的變動(dòng)是通過Object.defineProperty實(shí)現(xiàn)的,所以無法監(jiān)聽數(shù)組的添加操作是可以理解的,因?yàn)槭窃跇?gòu)造函數(shù)中就已經(jīng)為所有屬性做了這個(gè)檢測(cè)綁定操作。
但是官方的原文:由于 JavaScript 的限制, Vue 不能檢測(cè)以下變動(dòng)的數(shù)組:
當(dāng)你利用索引直接設(shè)置一個(gè)項(xiàng)時(shí),例如: vm.items[indexOfItem] = newValue
當(dāng)你修改數(shù)組的長(zhǎng)度時(shí),例如: vm.items.length = newLength
這句話是什么意思?我測(cè)試了下Object.defineProperty是可以通過索引屬性來設(shè)置屬性的訪問器屬性的,那為何做不了監(jiān)聽?
有些論壇上的人說因?yàn)閿?shù)組長(zhǎng)度是可變的,即使長(zhǎng)度為5,但是未必有索引4,我就想問問這個(gè)答案哪里來的,修改length,新增的元素會(huì)被添加到最后,它的值為undefined,通過索引一樣可以獲取他們的值,怎么就叫做“未必有索引4”了呢?
既然知道數(shù)組的長(zhǎng)度為何不能遍歷所有元素并通過索引這個(gè)屬性全部添加set和get不就可以同時(shí)更新視圖了嗎?
如果非要說的話,考慮到性能的問題,假設(shè)元素內(nèi)容只有4個(gè)有意義的值,但是長(zhǎng)度確實(shí)1000,我們不可能為1000個(gè)元素做檢測(cè)操作。但是官方說的由于JS限制,我想知道這個(gè)限制是什么內(nèi)容?各位大大幫我解決下這個(gè)問題,感謝萬分
你這個(gè)問題問的好,研究了下,雖然結(jié)果還是不知道,但對(duì)我而言還是有收獲的,這是我的一點(diǎn)心得和思考,希望對(duì)你有幫助
因?yàn)閿?shù)組不方便拓展
你既然測(cè)試了,應(yīng)該發(fā)現(xiàn)這個(gè)問題了啊
let list = []
Object.defineProperty(list, 0, {
get(){
console.log('get 0')
// 如果是對(duì)象,可以給對(duì)象拓展一個(gè)$data,用來存放真正的數(shù)據(jù),但數(shù)組不能.
// 只能放在別的地方,那顯然不科學(xué),不合理.
// 如果直接 return this[0],就遞歸了,爆棧
},
set (v) {
console.log('set o', v)
// 直接 this[0] = v,同樣爆棧
}
})
那就只能看不能用了
我最近剛好寫過Vue的Observer部分源碼分析博客
強(qiáng)答一波...
并不是說 JS 不能支持響應(yīng)式數(shù)組,沒有這種限制,而是一般開發(fā)者使用數(shù)組與使用對(duì)象的方法有區(qū)別。數(shù)組在 JS 中常被當(dāng)作棧,隊(duì)列,集合等數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)方式,會(huì)儲(chǔ)存批量的數(shù)據(jù)以待遍歷。并且編譯器對(duì)對(duì)象與數(shù)組的優(yōu)化也有所不同。
所以對(duì)數(shù)組的處理需要特化出來以提高性能。
Vue 中是通過對(duì) 每個(gè)鍵設(shè)置 getter/setter 來實(shí)現(xiàn)響應(yīng)式的,開發(fā)者使用數(shù)組,目的往往是遍歷,此時(shí)調(diào)用 getter 開銷太大了,所以 Vue 不在數(shù)組每個(gè)鍵上設(shè)置,而是在數(shù)組上定義 __ob__ ,并且替換了 push 等等能夠影響原數(shù)組的原型方法。
至于 length 的問題,你用 Object.keys() 或者 Object.getOwnPropertyNames() 就能獲得所有鍵的名字,前者是所有自有可枚舉的,后者是所有自有的,不需要用 length 。
從源碼可以清晰看到,Vue 跳過了對(duì)數(shù)組每個(gè)鍵設(shè)置響應(yīng)式的過程,而是直接對(duì)值進(jìn)行遞歸設(shè)置響應(yīng)式
export class Observer {
constructor(value: any) {
def(value, "__ob__", this);
if (Array.isArray(value)) {
// 替換原型(Object.setPrototype 這個(gè)方法執(zhí)行地比較慢,而且支持情況堪憂)
Object.setPrototypeOf(value, arrayMethods);
this.observeArray(value);
} else {
this.walk(value);
}
}
public walk(value: any) {
for (const key of Object.keys(value)) {
defineReactive(value, key);
}
}
public observeArray(items: any[]) {
// 設(shè)置 l = items.length 防止遍歷過程中 items 長(zhǎng)度變化
for (let i = 0, l = items.length; i < l; i++) {
// 直接觀察數(shù)組元素,省略在鍵上設(shè)置 getter/setter 的步驟
observe(items[i]);
}
}
}
而且樓主你造嗎?Vue 使用 $watch('arr') 是可以監(jiān)聽多維數(shù)組的,Vue 對(duì)普通對(duì)象和數(shù)組的設(shè)置情況是差異很大的。
另外還有就是樓上有人貼圖
這里面的$set支持設(shè)置數(shù)組+響應(yīng)式非數(shù)字鍵,Vue確實(shí)是這么支持的,然而?。∪绻诔跏蓟瘯r(shí)data里這么干,Vue會(huì)忽略非數(shù)字鍵的,不會(huì)變響應(yīng)式,它這是行為不一致!對(duì)它使用watch,直接修改它不會(huì)變,但修改數(shù)組就會(huì)觸發(fā)。
我早給Vue提issue了,但他們一直不理我。
https://github.com/vuejs/vue/...
歡迎閱讀我博客Vue Observer源碼分析,寫得非常詳細(xì)。
https://segmentfault.com/a/11...
北大青鳥APTECH成立于1999年。依托北京大學(xué)優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國(guó)IT技能型緊缺人才,是大數(shù)據(jù)專業(yè)的國(guó)家
達(dá)內(nèi)教育集團(tuán)成立于2002年,是一家由留學(xué)海歸創(chuàng)辦的高端職業(yè)教育培訓(xùn)機(jī)構(gòu),是中國(guó)一站式人才培養(yǎng)平臺(tái)、一站式人才輸送平臺(tái)。2014年4月3日在美國(guó)成功上市,融資1
北大課工場(chǎng)是北京大學(xué)校辦產(chǎn)業(yè)為響應(yīng)國(guó)家深化產(chǎn)教融合/校企合作的政策,積極推進(jìn)“中國(guó)制造2025”,實(shí)現(xiàn)中華民族偉大復(fù)興的升級(jí)產(chǎn)業(yè)鏈。利用北京大學(xué)優(yōu)質(zhì)教育資源及背
博為峰,中國(guó)職業(yè)人才培訓(xùn)領(lǐng)域的先行者
曾工作于聯(lián)想擔(dān)任系統(tǒng)開發(fā)工程師,曾在博彥科技股份有限公司擔(dān)任項(xiàng)目經(jīng)理從事移動(dòng)互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍(lán)懿科技有限責(zé)任公司從事總經(jīng)理職務(wù)負(fù)責(zé)iOS教學(xué)及管理工作。
浪潮集團(tuán)項(xiàng)目經(jīng)理。精通Java與.NET 技術(shù), 熟練的跨平臺(tái)面向?qū)ο箝_發(fā)經(jīng)驗(yàn),技術(shù)功底深厚。 授課風(fēng)格 授課風(fēng)格清新自然、條理清晰、主次分明、重點(diǎn)難點(diǎn)突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫(kù),具有快速界面開發(fā)的能力,對(duì)瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁(yè)制作和網(wǎng)頁(yè)游戲開發(fā)。
具有10 年的Java 企業(yè)應(yīng)用開發(fā)經(jīng)驗(yàn)。曾經(jīng)歷任德國(guó)Software AG 技術(shù)顧問,美國(guó)Dachieve 系統(tǒng)架構(gòu)師,美國(guó)AngelEngineers Inc. 系統(tǒng)架構(gòu)師。