Question d'entrevue Javascript: exécuter [1,2,3] .sum ()
Question d'entrevue Javascript: faire [1,2,3].sum()courir code exact sans utiliser Prototypeet Object.defineProperty, Object.defineProperties.
Puisqu'il s'agissait d'une question d'entrevue, je suppose qu'il existe des moyens de la faire fonctionner?
Toute aide / direction de pointage appréciée.
Merci
Réponses
Préface: Des questions comme celles-ci ne montrent pas vraiment que quelqu'un est un "bon" programmeur, cela signifie simplement qu'il est familier avec des astuces dans le langage qui ne conduisent pas à un code plus maintenable . Je me méfierais de travailler pour une entreprise ou une équipe qui utilise régulièrement des astuces comme celle-ci.
(Et dans mon cas personnel: j'ai travaillé sur le moteur JavaScript Chakra quand j'étais SE chez Microsoft et j'aime penser que je connais très bien JavaScript / ECMAScript et je devais encore réfléchir longtemps à la façon dont cela pourrait être fait sans en utilisant prototypeou defineProperty- c'est pourquoi je ne pense pas que ce soit une bonne question d'entretien technique s'ils s'attendaient à une réponse directe - mais s'il s'agissait d'une question d'entretien destinée à vous inciter à poser des questions à l'intervieweur, alors c'est différent).
Option 1: gestionnaire d'erreur global:
Voici une manière horrible :
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 a publié une version simplifiée qui évite eval, bien qu'elle utilise un 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: remplacer le Arrayconstructeur
Si vous utilisez un moteur JavaScript plus ancien (créé avant 2010 ou ECMAScript 5), alors un script qui remplace le Arrayconstructeur aura ce constructeur utilisé lorsque le script rencontre un littéral de tableau, et la .summéthode pourrait être ajoutée de cette façon:
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: être sournois avec la prototypepropriété:
Comme d'autres l'ont mentionné dans les commentaires, vous pouvez toujours muter le prototypemembre ou utiliser Object.definePropertysi vous accédez à ces membres sous forme de chaînes:
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 );
Combien pouvons-nous contourner les lignes ici?
En supposant que nous voulons que la ligne suivante fonctionne, [1, 2, 3].sum();nous pouvons très facilement lui faire faire quelque chose . Notez qu'en raison des règles d'insertion automatique de point-virgule , il n'est pas nécessaire que vous ayez un tableau. Il peut s'agir d'un accès au tableau avec un opérateur virgule .
({3: {sum: () => console.log(6)}}) //<-- object
[1,2,3].sum(); //<-- array access
Ou pour être plus clair, voici le code équivalent:
const obj = {
3: {
sum: () => console.log(6)
}
};
obj[3].sum(); //<-- array access
Depuis, je ne vois pas de définition de ce qu'il sumfaut faire, ce qui précède couvre toutes les exigences énumérées - pas de manigances de protoype, pas de propriétés supplémentaires.
OK, techniquement, sumne résume rien, mais voici une solution de contournement: définissez-le comme ceci
sum: (a, b) => a + b
Maintenant, c'est techniquement une fonction qui additionne deux nombres. Il n'est pas nécessaire de faire la somme de la séquence 1, 2, 3qui apparaît avant d'appeler le sum, après tout.
C'est une façon:
[1,2,3].__proto__.sum = () => { console.log('this runs!'); }
[1,2,3].sum();
Techniquement, vous n'utilisez pas Prototype, vous utilisez __proto__. Ce qui est le même avec un nom différent ... (mais pour les instances uniquement)