Domanda dell'intervista Javascript: esegui [1,2,3] .sum ()

Nov 17 2020

Javascript questione intervista: fare [1,2,3].sum()eseguire codice esatto senza l'utilizzo Prototypee Object.defineProperty, Object.defineProperties.

Dato che era una domanda da intervista, presumo che ci siano modi per farlo funzionare?

Qualsiasi aiuto / direzione di puntamento apprezzato.

Grazie

Risposte

8 Dai Nov 17 2020 at 03:09

Prefazione: Domande come queste non dimostrano che qualcuno sia un "buon" programmatore, significa semplicemente che ha familiarità con i trucchi nel linguaggio che non portano a un codice più manutenibile . Sarei diffidente nel lavorare per un'azienda o un team che utilizza regolarmente trucchi come questo.

(E nel mio caso personale: ho lavorato sul motore JavaScript Chakra quando ero un SE in Microsoft e mi piace pensare di conoscere JavaScript / ECMAScript molto bene e ho dovuto ancora pensare a lungo su come farlo senza usando prototypeo defineProperty- ecco perché non penso che questa sia una buona domanda di intervista tecnica se si aspettavano una risposta diretta - ma se questa era una domanda di intervista che ha lo scopo di indurti a porre domande all'intervistatore, allora è diverso).


Opzione 1: gestore degli errori globale:

Ecco un modo orribile :

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 ha pubblicato una versione semplificata che evita eval, sebbene utilizzi un locale try:

try {
    [1,2,3].sum()
} catch (err) {
    const result = err.message
    .match(/\[(.*?)\]/)[1]
    .split(',')
    .reduce((r, e) => r + +e, 0)
    
  console.log(result)
}

Opzione 2: sovrascrivi Arraycostruttore

Se stai utilizzando un motore JavaScript precedente (realizzato prima del 2010 o ECMAScript 5), uno script che sovrascrive il Arraycostruttore avrà quel costruttore utilizzato quando lo script incontra un array letterale e il .summetodo potrebbe essere aggiunto in questo modo:

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

Opzione 3: essere subdolo con la prototypeproprietà:

Come altri hanno menzionato nei commenti, puoi comunque modificare il prototypemembro o usarlo Object.definePropertyse accedi a quei membri come stringhe:

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

Quanto possiamo aggirare le righe qui?

Supponendo che vogliamo che la riga seguente funzioni, [1, 2, 3].sum();possiamo facilmente fargli fare qualcosa . Nota che a causa delle regole di inserimento automatico del punto e virgola , non è necessario quello che hai lì per essere un array. Potrebbe essere un accesso all'array con l' operatore virgola .

({3: {sum: () => console.log(6)}}) //<-- object

[1,2,3].sum(); //<-- array access

O per renderlo più chiaro, ecco il codice equivalente:

const obj = {
  3: {
    sum: () => console.log(6)
  }
};

obj[3].sum(); //<-- array access

Dal momento che non vedo una definizione di cosa sumdovrebbe fare, quanto sopra copre tutti i requisiti elencati: nessun protoipo shenanigans, nessuna proprietà extra.

OK, tecnicamente, sumnon somma nulla, ma ecco una soluzione alternativa: definiscila in questo modo

sum: (a, b) => a + b

Ora, è tecnicamente una funzione che somma due numeri. Non è necessario sommare la sequenza 1, 2, 3che appare prima di chiamare il sum, dopotutto.

2 LuisLimas Nov 17 2020 at 03:06

Questo è un modo:

 [1,2,3].__proto__.sum = () => { console.log('this runs!'); }
 
 [1,2,3].sum();

Tecnicamente non stai usando Prototype, stai usando __proto__. Che è lo stesso con un nome diverso ... (ma solo per istanze)