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
Share Improve this question edited Nov 16, 2020 at 20:26 gen_Eric 227k42 gold badges303 silver badges342 bronze badges asked Nov 16, 2020 at 19:54 serkanserkan 7,1514 gold badges42 silver badges50 bronze badges 7-
@Dai not really going to work - an array literal will not just lookup
Array
in the scope chain (that's whatnew Array()
would do) - it actually goes and initialises a native array, regardless of what occupieswindow.Array
. – VLAZ Commented Nov 16, 2020 at 19:58 - Did you sign a non-disclosure and agree not to share the interview questions? – anthumchris Commented Nov 16, 2020 at 19:59
-
@VLAZ Previously (like, before 2010) browsers would use a user-provided
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 -
1
What are the actual constraints? You aren't allowed to do anything with prototypes or you aren't allowed to use
prototype
as the property, or you aren't allowed to use the word "prototype"? Or what? – VLAZ Commented Nov 16, 2020 at 20:09 - 1 I mean.. the correct answer they are looking for could be "there is no (good) way to do this" perhaps to see if you're willing to give something hacky vs. put your foot down – CrayonViolent Commented Nov 16, 2020 at 20:31
3 Answers
Reset to default 9Preface: 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).
Option 1: Global error handler:
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)
}
Option 2: Override Array
constructor
If 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 );
Option 3: Being sneaky with the 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