【问题标题】:Run custom method on array update/create in JavaScript在 JavaScript 中对数组更新/创建运行自定义方法
【发布时间】:2021-02-16 08:35:47
【问题描述】:

我知道如何向对象添加自定义属性。

假设我有一个 foo 方法,

const foo = () => { console.log('custom method'); }

我可以将 foo 方法添加到 Array 原型中,并使用数组变量调用它

Array.prototype.foo = foo;

然后如果我创建一个名为的数组,

bar = [1, 2, 3];

然后运行

bar.foo()

它将执行我的自定义 foo 方法。但是我不知道每次创建数组和更新数组时如何运行foo方法。

我想在 JavaScript 中创建/更新数组期间运行自定义方法并存储一些数据。我该怎么做?

假设我有一个自定义方法,

const customMethod = () => {
   ...doing some stuff    
}

我希望每次创建数组时都运行此自定义方法并将一些数据存储在该数组中。就像我想找到数组的最大值并将其存储在带有键 maximum 的数组中,因为我们现在正在存储 length。因此,在创建/更新数组后,我不必计算最大值。我可以打电话给myArray.maximum 并获得最大值。

This approach 做了类似的事情。但是它需要添加事件侦听器和一个新的推送方法,以便每次使用该自定义推送方法将某些内容推送到数组中时它都可以触发一个事件。但在这种情况下,如果我使用常规 Array.prototype.push 方法或使用像这样的扩展运算符 newArr = [...oldArray, value] 创建一个新数组,我的自定义函数将不会更新。

更新:在搜索并借助评论中的链接后,我发现如果不扩展 Array 对象或从头开始创建自定义数组类型(即不可接受)。

我尝试扩展现有的 Array 类型并创建 MyCustomArray。但它根本不能用作数组。

class MyCustomArray extends Array {
   constructor(...args) {
      super(...args);
      console.log('custom array');
   }
}

知道如何扩展 Array 以创建我的 CustomArray 类型并向其添加侦听器,以便每次创建/更新 CustomArray 时它都会计算最大值并将其设置为数组 max 属性 (使用最少的代码更改)

所以我的 CustomArray 将像普通数组一样拥有所有方法和实例变量。但它会做一件额外的事情,每次我更新/创建一个 CustomArray 时,它都会计算该数组中的最大值并将其设置为属性。

【问题讨论】:

  • 这能回答你的问题吗? adding custom functions into Array.prototype
  • 并非如此。我一直在寻找在每次更新和创建数组期间自定义数组对象的方法。
  • "我知道如何向对象添加自定义属性" - 你能说明你的意思吗?也许有一些代码可以说明每次创建非数组对象或在其中存储数据时如何运行自定义方法?
  • 就像我可以这样做将foo 方法添加到数组原型并使用数组变量调用它。 Array.prototype.foo = foo; 。然后,如果我创建一个名为bar 的数组并运行bar.foo(),它将执行我的自定义 foo 方法。但我不知道每次创建数组和更新数组时如何运行foo 方法。
  • @sabbir.alam 你不能那样做,不可能劫持“每个数组”。不过,您可以显式包装一些特定的数组,以便控制它们的更新方式,并且在更新期间还可以做任何您想做的事情。

标签: javascript arrays prototype


【解决方案1】:

我认为你不能像那样“劫持”所有数组。即使您对本机 Array 函数进行修补,使用文字符号(即 [])创建的数组也不会受到影响:

console.log(new Array(1,2,3));
console.log([4,5,6]);

Array = function () {
  throw new Error;
};

try {
  console.log(new Array(1,2,3));
} catch (e) {
  console.log('Cannot create array with new Array');
}

console.log([4,5,6]);

您可能认为您需要将数组传递给其他东西。您只需要选择适合您的解决方案。我个人会尝试使用代理:

const spy =
  (arr, fn) =>
    new Proxy(arr, {
      get(target, prop) {
        if (prop === "max") {
          return Math.max(...target);
        }
        if (prop === "min") {
          return Math.min(...target);
        }
        if (typeof target[prop] === "function") {
          fn();
        }
        return target[prop];
      }
    });


const arr = spy([1,2,3], () => console.log('spied'));
arr.push(500);
arr.push(-10);

console.log(arr.min, arr.max, JSON.stringify(arr), Array.isArray(arr));

我喜欢代理的地方在于它可以设计成不会妨碍它。在上面的示例中,arr 仍然是一个数组。你可以做你以前做的所有正常的事情。例如 Array.isArray 仍然返回 true 并且 JSON.stringify 仍然产生预期的结果。

但是请注意,在上面的实现中,如果您从 arr 生成另一个数组,它不会被自动代理:

const arr = spy([1,2,3], fn);
arr.slice(1); // [2,3] (non-proxied array!)

【讨论】:

  • 你的意思是代理是针对单个数组实例的,对吧?
  • @sabbir.alam 是的。但我确信我们可以编写一个返回另一个代理的代理。
  • 现在,这简直是在我头上。一些理解代理的指针会很好,我可以看到这种返回新代理的模式。
  • 一个题外话的问题,为什么每个人都像这样双引号劫持"hijack"? :)
  • @sabbir.alam 我只是想说你不能像免费那样自动拦截所有的电话。 (不过我的意思不是坏话:)
【解决方案2】:

嗯,它有点蛮力,但是,Array 有点像special,如果你提供一个扩展类的构造函数,它的方法创建新数组将使用该构造函数,因此,例如,myCustomArray.filter 将产生 myCustomArray 对象结果而不是 Array 对象结果。 (如果你不提供构造函数,这不起作用)。

如果我想随时访问该自定义类型中 Array 的特定自定义功能,我可能会在创建时将值设为 null,并将更改现有对象的方法(如 pop)扩展为 null 它同样,然后有一个方法可以提供非空缓存值,或者计算、缓存并返回当前值。

我没有仔细计算,但我认为只有少数数组方法可以更改现有数组(而不是创建新数组),因此应该不需要太多努力。

【讨论】:

    猜你喜欢
    • 2016-08-16
    • 2010-10-05
    • 2023-03-30
    • 2013-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-22
    • 2010-11-05
    相关资源
    最近更新 更多