《深入理解ES6》阅读随笔
数组代理
在 ES6 之前,在 JavaScript 中是无法直接创建数组对象的,但是在 ES6 中,可以通过代理的方式来模拟实现一个数组对象。
数组到底实现了什么功能
数组是一个可以动态增减元素并且实时更新数组长度 length 的对象,下面是一个简单的实现案例:
let arr = new Array(2)
console.log(arr.length) // 2
arr[0] = 'a'
arr[1] = 'b'
arr[2] = 'c'
console.log(arr) // [ 'a', 'b', 'c']
console.log(arr.length) // 3
console.log(arr[1]) // a
arr.length = 1
console.log(arr.length) // 1
console.log(arr[1]) // undefined
从上面的例子中可以归纳出:
- 当给数组索引赋值时,如果该索引已存在,那么值更新,如果赋值大于数组长度,那么还需要更新 length;
- 当直接修改 length 时,如果赋值元素比数组长度长,那么只需更新 length,如果赋值元素比数组长度短时,还需要删除原来多出来的那部分元素。
检索数组索引
判断新的键是否满足数组索引键的条件:
function toUnit32(value) {
return Math.floor(Math.abs(Number(value)) % Math.pow(2, 32))
}
function isArrayIndex(key) {
const numericKey = toUnit32(key)
return numericKey == String(numericKey) && numericKey < (Math.pow(2, 32) - 1)
}
新增元素 length 递增和设置 length 删除元素
通过代理创建类数组对象:
function toUnit32(value) {
return Math.floor(Math.abs(Number(value)) % Math.pow(2, 32))
}
function isArrayIndex(key) {
const numericKey = toUnit32(key)
return numericKey == String(numericKey) && numericKey < (Math.pow(2, 32) - 1)
}
function createArray(length = 0) {
return new Proxy({
length
}, {
set(trapTargat, key, value) {
const currentLength = Reflect.get(trapTargat, 'length')
if (isArrayIndex(key)) {
if (Number(key) >= currentLength) {
Reflect.set(trapTargat, 'length', currentLength + 1)
}
} else if (key === 'length') {
if (value < currentLength) {
for (let i = currentLength - 1; i >= value; i--) {
Reflect.deleteProperty(trapTargat, i)
}
}
}
return Reflect.set(trapTargat, key, value)
}
})
}
const arr = createArray(2)
console.log(arr.length) // 2
arr[0] = 'a'
arr[1] = 'b'
arr[2] = 'c'
console.log(arr.length) // 3
console.log(arr[1]) // a
arr.length = 1
console.log(arr.length) // 1
console.log(arr[1]) // undefined
自定义代理数组类
将代理实现类数组对象封装为一个类实现:
function toUnit32(value) {
return Math.floor(Math.abs(Number(value)) % Math.pow(2, 32))
}
function isArrayIndex(key) {
const numericKey = toUnit32(key)
return numericKey == String(numericKey) && numericKey < (Math.pow(2, 32) - 1)
}
class MyArray {
constructor(length = 0) {
this.length = length
return new Proxy({
length
}, {
set(trapTargat, key, value) {
const currentLength = Reflect.get(trapTargat, 'length')
if (isArrayIndex(key)) {
if (Number(key) >= currentLength) {
Reflect.set(trapTargat, 'length', currentLength + 1)
}
} else if (key === 'length') {
if (value < currentLength) {
for (let i = currentLength - 1; i >= value; i--) {
Reflect.deleteProperty(trapTargat, i)
}
}
}
return Reflect.set(trapTargat, key, value)
}
})
}
}
const arr = createArray(2)
console.log(arr.length) // 2
arr[0] = 'a'
arr[1] = 'b'
arr[2] = 'c'
console.log(arr.length) // 3
console.log(arr[1]) // a
arr.length = 1
console.log(arr.length) // 1
console.log(arr[1]) // undefined
网友评论