Intercepting Access to a JavaScript Array

I would like to associate some side effect with each accessory of the array, for example a[i] . For example, if a side effect writes a message to the console, the following program:

 var array = [1, 2, 3] var total = 0; for (var i in array) { total += array[i] } console.log(total); 
should return the result as follows:

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

In case I was interested in intercepting the push array method, I would use the technique from this post blog and provide an interceptor:

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

Is it possible to apply the same trick to an array accessory? Or what would be the best solution for this problem? It is important to note that I do not want to change the source code of the program. So using JS proxies to intercept getters and setters does not seem like a viable option for my problem.

One specific side effect that I want to introduce is to throw an exception when the available value is undefined (some variation of index exclusion from restrictions for JS arrays.) I would check if the current available value is equal to undefined , in which case throw an exception, otherwise just return the original value.

+5
source share
2 answers

You cannot override this accessory arrays. Here is an example:

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

But if you try to do the same with a property that does not actually exist in the array, you will achieve it:

 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 

What you can do is a small workaround for accessing elements using the get method of arrays.

 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! 

So, back to your question, you could do something like push , but with get , avoiding the proxy:

 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); 

Just to complete the answer, what you are trying to do can be done on one line using the reduce method of arrays:

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

I highly recommend that you avoid overriding these accessories. You will change the basis of the code so that outsiders can not understand what is happening without reading the entire code. In addition, you will lose many built-in useful methods. Hope this helps

ps following your edit, to check for undefined values โ€‹โ€‹and raise exceptions, you can add a check inside an override of the get method. But my suggestion is only to filter the array, determine the undefined values โ€‹โ€‹and get rid of them. Please note that I am using double equal. because undefined == null , but undefined !== null . This way you remove both undefined and null values. If you want to remove only undefined, change it to if (typeof element === 'undefined') .

So, something like this, using only one loop with the filter arrays method:

 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 
+3
source

This is not possible without changing the code:

So, you need to either modify the code, or pre-process your code, or change the JavaScript mechanism that works with the code.

In the first two cases, I recommend replacing array literals with explicit calls to the Array constructor, which can be overridden:

 // 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); 
+2
source

Source: https://habr.com/ru/post/1268066/


All Articles