Question d'entrevue Javascript: exécuter [1,2,3] .sum ()

Nov 17 2020

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

8 Dai Nov 17 2020 at 03:09

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

6 VLAZ Nov 17 2020 at 03:26

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.

2 LuisLimas Nov 17 2020 at 03:06

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)