我想将一些副作用与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数组的索引超出范围异常的一些变化。)我将检查当前访问的值是否等于{ {1}},并在这种情况下抛出异常,否则只返回原始值。
答案 0 :(得分:3)
您无法覆盖Arrays的访问者。 这是一个例子:
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

您可以做的是通过数组的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);
&#13;
只是为了完成答案,你可以用reduce
数组方法在一行中完成你想要做的事情:
var array = [1, 2, 3];
var result = array.reduce(function (accumulator, actual) {
return accumulator + actual;
}, 0);
console.log(result);
&#13;
我强烈建议您避免覆盖这些访问者。您将更改代码的基础,以便第三方人无法在不阅读所有代码的情况下了解正在进行的操作。此外,您将失去许多内置的有用方法。 我希望这有帮助
P.S。在编辑之后,为了检查未定义的值并引发异常,您可以在get方法的覆盖中添加检查。
但我的建议只是过滤数组,检测未定义的值并摆脱它们。
请注意,我使用双倍相等。因为undefined == null
但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
&#13;
答案 1 :(得分:2)
如果不修改代码,则无法实现:
您无法覆盖数组文字构造函数。请参阅Overwriting the Array constructor does not affect [], right?
您也无法覆盖for ... in循环使用的迭代器的行为。请参阅https://tc39.github.io/ecma262/#sec-enumerate-object-properties
虽然可以在Array.prototype
上添加具有拦截getter函数的属性,但是当数组实例上存在同名属性时,将不会访问这些原型属性,如示例中所示。 / p>
因此,您需要修改代码,预处理代码或修改运行代码的JavaScript引擎。
在前两种情况下,我建议使用对Array
构造函数的显式调用替换数组文字,可以覆盖:
// Override default array constructor:
Array = (function(Array) {
function LoggingArray(...args) {
return new Proxy(Array(...args), {
get: function(target, property) {
console.log(target[property]);
return Reflect.get(target, property);
}
});
}
Object.setPrototypeOf(LoggingArray, Array);
LoggingArray.prototype = Array.prototype;
return LoggingArray;
})(Array);
// Original code without array literal:
var array = Array(1, 2, 3);
var total = 0;
for (var i in array) {
total += array[i]
}
console.log(total);