这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战
熟悉Python、Ruby或Perl的同学,可能习惯了数组的负索引,它使得你可以使用负索引来逆向检索数组元素,代码如下所示:
但是我们知道 JS 中并不存在负索引这种用法,今天我们就来模拟一下负索引的实现。
function createNegativeArrayProxy(array){
// 如果传入的参数不是数组,则抛出异常
if(!Array.isArray(array)){
throw new TypeError('Expected an array');
}
//返回新的代理,新代理用传入的数组为代理目标。
return new Proxy(array, {
get: (target, index)=>{
index= +index;
return target[index<0?target.length+index:index];
},
set: (target, index, val)=>{
index = + index;
return target[index<0?target.length+index:index]=val;
}
})
}
const arr = ['aa', 'bb', 'cc'];
const proxyArr = createNegativeArrayProxy(arr);
console.log(arr[-2]);//undefinded
console.log(proxyArr[-2]);//bb
到这里,我们就实现了数组的负索引。但是需要注意的是,在Chrome浏览器,代理数组的执行时间大约为正常数组的50倍,在Firefox浏览器大约为20倍。因此,要谨慎使用代理,尽管使用代理可以创造性地控制对象的访问,但是大量的控制操作将带来性能问题。
知识拓展:Proxy 拓展
这里补充一下代理的基础知识,给不熟悉这部分知识的小伙伴补补课。
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
语法
const p = new Proxy(target, handler)
参数:
-
target:需要使用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。 -
handler: 一个对象,其属性是当执行一个操作时定义代理的行为的函数(可以理解为某种触发器)。
基础示例
在以下简单的例子中,当对象中不存在属性名时,默认返回值为 37。下面的代码以此展示了 get handler 的使用场景。
const handler = {
get: function(obj, prop) {
return prop in obj ? obj[prop] : 37;
}
};
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37
无操作转发代理:
代理会将所有应用到它的操作转发到这个对象上。
let target = {};
let p = new Proxy(target, {});
p.a = 37; // 操作转发到目标
console.log(target.a); // 37. 操作已经被正确地转发