Pytanie do wywiadu Javascript: make [1,2,3] .sum () run

Nov 17 2020

Javascript wywiad pytanie: podać [1,2,3].sum()dokładny przebieg kod bez korzystania Prototypei Object.defineProperty, Object.defineProperties.

Ponieważ było to pytanie do wywiadu, zakładam, że są sposoby, aby to zadziałało?

Każda pomoc / wskazanie kierunku jest mile widziane.

Dzięki

Odpowiedzi

8 Dai Nov 17 2020 at 03:09

Przedmowa: Takie pytania tak naprawdę nie pokazują, że ktoś jest „dobrym” programistą, oznacza to po prostu, że zna sztuczki w języku, które nie prowadzą do kodu łatwiejszego w utrzymaniu . Obawiałbym się pracy w firmie lub zespole, który regularnie stosuje takie sztuczki.

(A w moim osobistym przypadku: pracowałem nad silnikiem Chakra JavaScript, kiedy byłem SE w Microsoft i lubię myśleć , że znam JavaScript / ECMAScript bardzo dobrze i wciąż musiałem długo się zastanawiać, jak można to zrobić bez używając prototypelub defineProperty- dlatego uważam, że nie jest to dobre techniczne pytanie do rozmowy kwalifikacyjnej, jeśli oczekiwali bezpośredniej odpowiedzi - ale jeśli było to pytanie do rozmowy kwalifikacyjnej, które ma zachęcić cię do zadawania pytań ankieterowi, to jest inaczej).


Opcja 1: Globalna obsługa błędów:

Oto okropny sposób:

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 opublikował uproszczoną wersję, która unika eval, chociaż używa lokalnego try:

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

Opcja 2: Zastąp Arraykonstruktora

Jeśli używasz starszego silnika JavaScript (wyprodukowanego przed 2010 lub ECMAScript 5), wtedy skrypt, który nadpisuje Arraykonstruktor, będzie miał ten konstruktor używany, gdy skrypt napotka literał tablicy, a .summetodę można dodać w ten sposób:

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

Opcja 3: Podstępne obchodzenie się z prototypenieruchomością:

Jak wspominali inni w komentarzach, nadal możesz zmodyfikować prototypeczłonka lub użyć, Object.definePropertyjeśli uzyskujesz dostęp do tych członków jako ciągów:

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

Jak bardzo możemy tutaj ominąć linie?

Zakładając, że chcemy, aby następująca linia działała [1, 2, 3].sum();, możemy bardzo łatwo po prostu sprawić, by coś zrobiła . Zwróć uwagę, że ze względu na zasady automatycznego wstawiania średników nie jest konieczne, aby to, co masz, było tablicą. Może to być dostęp do tablicy z operatorem przecinka .

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

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

Aby było to bardziej zrozumiałe, oto kod równoważny:

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

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

Ponieważ nie widzę definicji tego, co sumpowinienem zrobić, powyższe obejmuje wszystkie wymienione wymagania - bez shenaniganów protoype, bez dodatkowych właściwości.

OK, technicznie rzecz biorąc, sumnic nie sumuje , ale tutaj jest obejście: zdefiniuj to w ten sposób

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

Z technicznego punktu widzenia jest to funkcja sumująca dwie liczby. W końcu nie jest wymagane sumowanie sekwencji, 1, 2, 3która pojawia się przed wywołaniem metody sum.

2 LuisLimas Nov 17 2020 at 03:06

To jest jeden sposób:

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

Technicznie rzecz biorąc, nie używasz Prototype, używasz __proto__. Który jest taki sam z inną nazwą ... (ale tylko dla instancji)