jjzjj

javascript - 拦截 JavaScript 数组访问器

coder 2025-03-22 原文

我想将一些副作用与每个数组访问器相关联,例如 a[i]。例如,如果副作用是向控制台写入消息,则以下程序:

var array = [1, 2, 3]
var total = 0;
for (var i in array) {
  total += array[i]
}
console.log(total);
应该返回如下输出:

1 // access a[0]
2 // access a[1]
3 // access a[2]
6 // print original total

如果我对拦截数组方法 push 感兴趣,我会使用此博客中的技术 post并提供了一个拦截器:

var _push = Array.prototype.push;
Array.prototype.push = function( item ) {
    console.log( 'pushing ', item, ' into ', this );
    _push.apply( this, arguments );
}

是否可以将相同的技巧应用于数组访问器?或者什么是解决这个问题的更好方法?一个重要的注意事项是我不想修改程序的原始代码。因此,使用 JS proxies 拦截 getter 和 setter 似乎不是解决我的问题的有效选项。

我想介绍的一个特别的副作用是在访问的值未定义的情况下引发异常(JS 数组的索引越界异常的一些变体。)我会检查当前访问的值是否等于 undefined,并抛出异常,在这种情况下,否则只返回原始值。

最佳答案

您不能覆盖数组的访问器。 举个例子:

Object.defineProperty(Array.prototype, 0, {
  get: function () { return "my get on 0"; }
});
var a = [1,2,3];
console.log(a[0]); // output: 1

但是,如果您尝试对数组中实际上不存在的属性执行相同的操作,您将实现它:

Object.defineProperty(Array.prototype, 5, {
  get: function () { return "my get on 5"; }
});
var a = [1,2,3];
console.log(a[5]); // output: my get on 5

您可以做的是通过 Arrays 的 get 方法访问元素的一些变通方法。

Array.prototype.get = function(i) { 
  console.log('my print'); 
  console.log(this[i]); 
  return "this is!"; 
};
var a = [1,2,3];
console.log(a.get(0)); // output: my print 1 this is!

因此,回到您的问题,您可以像为 push 那样做一些事情,但是使用 get,避免代理:

Array.prototype.get = function (i) {
  console.log('Accessing element: ' + this[i]);
  console.log(this);
  return this[i];
};
var array = [1, 2, 3];
var total = 0;
// be careful that now you cannot do anymore 
// for (var i in array), because inside the array there is also the property get defined and it will cycle also on that
// if you want to cycle again in that way, you need the check through hasOwnProperty method
/*
for(var i in array) {
  if (array.hasOwnProperty(i)){
    console.log(i);
    total += array.get(i);
  } 
}
*/
for(var i = 0; i < array.length; i++) {
  total += array.get(i);
}
console.log(total);

只是为了完成答案,您尝试做的事情可以用数组的 reduce 方法在一行中完成:

var array = [1, 2, 3];
var result = array.reduce(function (accumulator, actual) {
  return accumulator + actual;
}, 0);
console.log(result);

我强烈建议您避免覆盖这些访问器。您将更改代码的基础,这样第三方人员就不可能在不阅读所有代码的情况下理解发生了什么。此外,您将失去很多内置的有用方法。 希望对您有所帮助

附注在您的编辑之后,为了检查未定义的值并引发异常,您可以在 get 方法的覆盖范围内添加检查。 但我的建议只是过滤数组,检测未定义的值并删除它们。 请注意,我使用的是双等号。因为 undefined == null 但是 undefined !== null。 通过这种方式,您将删除未定义值和空值。如果您只想删除未定义的,请将其更改为 if (typeof element === 'undefined')

像这样,只使用一个循环和数组 filter 方法:

var data = [1, 2, undefined, 3, 4, undefined, 5];

data = data.filter(function( element, index ) {
   // note that I am using the double equal. because undefined == null but undefined !== null. 
   // in this way you will remove both undefined and null values
   // if you want to remove only undefined, change it to if (typeof element === 'undefined')
   if (element == null) {
     console.log('found and undefined null value at index: ' + index);
   }
   return element != null;
});
console.log(data); // array without undefined and null values

关于javascript - 拦截 JavaScript 数组访问器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44097191/

有关javascript - 拦截 JavaScript 数组访问器的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  3. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  4. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  5. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  6. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  7. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  8. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  9. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  10. ruby - 在 Ruby 中用键盘诅咒数组浏览 - 2

    我正在尝试在Ruby中制作一个cli应用程序,它接受一个给定的数组,然后将其显示为一个列表,我可以使用箭头键浏览它。我觉得我已经在Ruby中看到一个库已经这样做了,但我记不起它的名字了。我正在尝试对soundcloud2000中的代码进行逆向工程做类似的事情,但他的代码与SoundcloudAPI的使用紧密耦合。我知道cursesgem,我正在考虑更抽象的东西。广告有没有人见过可以做到这一点的库或一些概念证明的Ruby代码可以做到这一点? 最佳答案 我不知道这是否是您正在寻找的,但也许您可以使用我的想法。由于我没有关于您要完成的工作

随机推荐