js运用代理实现数组负索引

384 阅读2分钟

这是我参与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. 操作已经被正确地转发