舉個例子,來說明下為什麼監聽不到陣列變化
var target =從本例中可以看到,當taget.val被設定為陣列後,想要對陣列內部進行修改,通過陣列索引去賦值target.val[1]=10,不會觸發set方法執行。那麼該如何實現呢?let _value =target.val
object.defineproperty(target,"val",,
set:
function
(newval)
})console.log(target.val) //1
console.log(target.val = ) //
setted
console.log(target.val = [1,2,3]) //
setted [1,2,3]
console.log(target.val[1]=10) //
10console.log(target.val.push(8)) //
4console.log(target.val.length=5) //
5console.log(target.val) //
[1, 10, 3, 8, empty]
我們先來了解下 array.prototype.push.call() 相關知識,便於監聽陣列,實現響應做鋪墊。
var a = [1,2,3];注:合併陣列為什麼不直接使用array.prototype.concat()呢?var b = [4,5,6];
console.log(a)
//[1,2,3,4,5,6]
列印結果看來,陣列的隱式原型上掛載了一些方法,如push()、pop()、shift()、unshift()、splice()、sort()、reverse()等。
我們重新改寫下方法
let arr = [1,2,3]arr.__proto__ =
}arr.push(6)
console.log('修改後陣列:',arr)
在官方文件,所需監視的只有 push()、pop()、shift()、unshift()、splice()、sort()、reverse() 7 種方法。我們可以遍歷一下:
只需要監聽我們需要監聽的資料陣列的乙個變更,而不是針對原生array的乙個重新封裝。
會重寫array.prototype.push方法,並生成乙個新的陣列賦值給資料,這樣資料雙向繫結就會觸發。
首先讓這個物件繼承
array
本身的所有屬性,這樣就不會影響到陣列本身其他屬性的使用,後面對相應的函式進行改寫,也就是在原方法呼叫後去通知其它相關依賴這個屬性發生了變化,這點和object.defineproperty
中setter
所做的事情幾乎完全一樣,唯一的區別是可以細化到使用者到底做的是哪一種操作,以及陣列的長度是否變化不會汙染到原生array上的原型方法。
首先我們將需要監聽的陣列的原型指標指向newarrproto,然後它會執行原生array中對應的原型方法,與此同時執行我們自己重新封裝的方法。
那麼問題來了,這種形式咋這麼眼熟呢?這不就是我們見到的最多的繼承問題麼?子類(newarrproto)和父類(array)做的事情相似,卻又和父類做的事情不同。但是直接修改__proto__隱式原型指向總感覺心裡怪怪的(因為我們可能看到的多的還是prototype),心裡不(w)舒(t)服(f)。
const arrayproto =array.prototype;const arraymethods =object.create(arrayproto);
const newarrproto =;
['push', 'pop','shift','unshift','splice','sort','reverse'].foreach(method =>
})let list1 = [1, 2];
//將我們要監聽的陣列的原型指標指向上面定義的空陣列物件
//newarrproto的屬性上定義了我們封裝好的push,pop等方法
list1.__proto__ =newarrproto;
list1.push(3); //
監聽到陣列的變化啦! 3
//list2沒有被重新定義原型指標,所以這裡會正常執行原生array上的原型方法
let list2 = [1, 2];
list2.push(3); //
3
var obj ={}通過上面對比結果,我們可以看出:console.log(array.prototype.push.call(obj, 'a','b','c')) //
3console.log(obj) //
var obj1 =
console.log(array.prototype.push.call(obj1, 'a','b','c')) //
8console.log(obj1) //
var obj2 =
console.log(array.prototype.push.call(obj2, 'a','b','c')) //
10console.log(obj2) //
1)當物件中不含有length屬性時,呼叫陣列原型方法push,將物件轉為類陣列物件,新增屬性的索引從0開始,且lengt指是新增屬性的個數
2)當物件中含有length屬性時,新增屬性的索引命名從length長度開始計算。
eg: obj1中length為5,新增加屬性的索引分別為5、6、7;obj2中length為7,新增加屬性的索引分別為7、8、9
array.prototype.slice.call()方法是只能在類陣列上起作用的,並不能同push()方法一樣可以可以使物件轉換為帶有length屬性的類陣列物件。
結論,當物件中沒有length屬性時,預設新增的新屬性索引應為0,因為a中已經有為0的key了,於是將原來的banana覆蓋了,便有了現在的結果。
KVO監聽陣列變化
1 某乙個類.h檔案 新建乙個model類 裡面有待監聽selectarray 待監聽陣列模型類 inte ce selectarraymodel nsobject 勾選儲存陣列 property nonatomic,strong nsmutablearray selectarray end 2 某...
iOS KVO 監聽陣列變化
首先,陣列不能直接使用kvo使用監聽。當我們想要使用kvo監聽陣列,我們需要進行一下幾步。1.kvo不能監聽uiviewcontroller中的陣列。我們需要先建立乙個模型,將陣列新增值模型中。inte ce selectedsarr nsobject property nonatomic,stro...
vue監聽陣列變化
1 觸發更新檢視 2function updateview 56 重新定義陣列原型 7 const oldarrayproperty array.prototype8 建立新物件,原型指向 oldarrayproperty 再擴充套件新的方法不會影響原型 9 const arrproto objec...