上篇 Vue數(shù)據(jù)響應(yīng)原理(二)—— 數(shù)組的響應(yīng) 中是鬼,沒有考慮兼容性問題肤舞,__proto__
屬性在 IE10 以及更低版本 IE 中是不支持的,需實(shí)現(xiàn)兼容方案均蜜。
思路就是直接在數(shù)組實(shí)例上面定義新的同名變異方法作為“攔截器”:
const mutationMethods = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
const arrayMethods = Object.create(Array.prototype)
const arrayProto = Array.prototype
mutationMethods.forEach(method => {
arrayMethods[method] = function (...args) {
const result = arrayProto[method].apply(this, args)
console.log(`我截獲了對(duì)數(shù)組的${method}操作`)
return result
}
})
const arr = ['kobe', 'jordan']
mutationMethods.forEach(method => {
arr[method] = arrayMethods[method]
})
arr.push('wade') // '我截獲了對(duì)數(shù)組的push操作'
console.log(JSON.stringify(arr)) // '["kobe","jordan","wade"]'
數(shù)組變異方法擴(kuò)展功能以及原功能均正常李剖。
但仍然有一個(gè)問題:
console.log(JSON.stringify(Object.keys(arr))) // ["0","1","2","push","pop","shift","unshift","splice","sort","reverse"]
直接添加到數(shù)組實(shí)例上的這些方法都是可枚舉的,按理說囤耳,數(shù)組本身的變異方法不應(yīng)該被枚舉出來篙顺。
那么,使用 Object.defineProperty
將其定義為不可枚舉:
mutationMethods.forEach(method => {
Object.defineProperty(arr, method, {
enumerable: false,
writable: true,
configurable: true,
value: arrayMethods[method]
})
})
arr.push('wade') // '我截獲了對(duì)數(shù)組的push操作'
console.log(JSON.stringify(arr)) // '["kobe","jordan","wade"]'
console.log(JSON.stringify(Object.keys(arr))) // '["0","1","2"]'
那么低版本 IE 的兼容代碼就成了這樣:
const mutationMethods = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
const arrayMethods = Object.create(Array.prototype)
const arrayProto = Array.prototype
mutationMethods.forEach(method => {
arrayMethods[method] = function (...args) {
const result = arrayProto[method].apply(this, args)
console.log(`我截獲了對(duì)數(shù)組的${method}操作`)
return result
}
})
const arr = ['kobe', 'jordan']
mutationMethods.forEach(method => {
Object.defineProperty(arr, method, {
enumerable: false,
writable: true,
configurable: true,
value: arrayMethods[method]
})
})
結(jié)合上一篇充择,便可實(shí)現(xiàn)最終兼容方案:
const mutationMethods = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
const arrayMethods = Object.create(Array.prototype)
const arrayProto = Array.prototype
mutationMethods.forEach(method => {
arrayMethods[method] = function (...args) {
const result = arrayProto[method].apply(this, args)
console.log(`我截獲了對(duì)數(shù)組的${method}操作`)
return result
}
})
const arr = ['kobe', 'jordan']
if ('__proto__' in {}) {
arr.__proto__ = arrayMethods
} else {
mutationMethods.forEach(method => {
Object.defineProperty(arr, method, {
enumerable: false,
writable: true,
configurable: true,
value: arrayMethods[method]
})
})
}