Javascript interview question: make [1,2,3].sum()
exact code run without using Prototype
and Object.defineProperty
, Object.defineProperties
.
Since it was an interview question I am assuming there are ways to make it work?
Any help/pointing direction appreciated.
Thanks
Javascript interview question: make [1,2,3].sum()
exact code run without using Prototype
and Object.defineProperty
, Object.defineProperties
.
Since it was an interview question I am assuming there are ways to make it work?
Any help/pointing direction appreciated.
Thanks
Array
in the scope chain (that's what new Array()
would do) - it actually goes and initialises a native array, regardless of what occupies window.Array
.
– VLAZ
Commented
Nov 16, 2020 at 19:58
Array
constructor when it encounters literals. JavaScript array literals are not initialized by the parser/piler but when encountered.
– Dai
Commented
Nov 16, 2020 at 19:59
prototype
as the property, or you aren't allowed to use the word "prototype"? Or what?
– VLAZ
Commented
Nov 16, 2020 at 20:09
Preface: Questions like these don't really show someone is a "good" programmer, it just means they're familiar with tricks in the language that do not lead to more-maintainable code. I'd be wary of working for a pany or team that regularly uses tricks like this.
(And in my personal case: I worked on the Chakra JavaScript engine when I was an SE at Microsoft and I like to think that I know JavaScript/ECMAScript very well and I still had to think a long time about how this could be done without using prototype
or defineProperty
- so that's why I don't think this is a good technical interview question if they expected a straight-answer - but if this was an interview question that's meant to prompt you into asking questions of the interviewer then that's different).
Here's a horrible way:
window.addEventListener( 'error', function( e ) {
if( e.error instanceof ErrorEvent || e.error instanceof TypeError ) {
const msg = e.error.message;
const suffixIdx = msg.indexOf( ".sum is not a function" );
if( suffixIdx > -1 ) {
const arrayStr = msg.substring( 0, suffixIdx );
const arr = eval( arrayStr ); // <-- lolno
const total = arr.reduce( ( sum, e ) => sum + e, 0 );
console.log( total ); // 6
}
}
} );
[1,2,3].sum()
@NenadVracar has posted a simplified version that avoids eval
, though it uses a local try
:
try {
[1,2,3].sum()
} catch (err) {
const result = err.message
.match(/\[(.*?)\]/)[1]
.split(',')
.reduce((r, e) => r + +e, 0)
console.log(result)
}
Array
constructorIf you're using an older JavaScript engine (made prior to 2010 or ECMAScript 5) then a script that overrides the Array
constructor will have that constructor used when the script encounters an array literal, and the .sum
method could be added that way:
Array = function() { // <-- THIS WILL NOT WORK IN BROWSERS MADE AFTER 2010!
this.sum = function() {
var total = 0;
for( var i = 0; i < this.length; i++ ) {
total += this[i];
}
return total;
};
};
let total = [1,2,3].sum();
console.log( total );
prototype
property:As others have mentioned in the ments, you could still mutate the prototype
member or use Object.defineProperty
if you access those members as strings:
Array[ 'proto' + 'type' ].sum = function() {
var total = 0;
for( var i = 0; i < this.length; i++ ) {
total += this[i];
}
return total;
};
let total = [1,2,3].sum();
console.log( total );
How much can we skirt the lines here?
Assuming that we want the following line to work [1, 2, 3].sum();
then we can very easily just make it do something. Note that due to the automatic semicolon insertion rules, it's not necessary what you have there to be an array. It might be array access with ma operator in it.
({3: {sum: () => console.log(6)}}) //<-- object
[1,2,3].sum(); //<-- array access
Or to make it more clear, here is the equivalent code:
const obj = {
3: {
sum: () => console.log(6)
}
};
obj[3].sum(); //<-- array access
Since, I don't see a definition of what sum
should do, the above covers all the requirements listed - no protoype shenanigans, no extra properties.
OK, technically, sum
doesn't sum anything, but here is a workaround: define it like this
sum: (a, b) => a + b
Now, it's technically a function that sums two numbers. There is no requirement to sum the sequence 1, 2, 3
that appears before calling the sum
, after all.
Use pizza, no Prototype
needed