javascript - Șir de șabloane ca nume de proprietate a obiectului


De ce JavaScript nu permite un șir șablon ca și cheie a unei proprietăți a obiectului? De exemplu, când introduc:

foo = {`bar`: 'baz'}

în REPL-ul NodeJS, aruncă un SyntaxError cu „Unexpected template string” și un lung stack trace. Valorile proprietăților sunt însă în regulă, ceea ce nu este atât de neașteptat. Erori similare apar și în browser, de exemplu, Firebug aruncă un SyntaxError cu „invalid property id”.

Șirurile șablon sunt permise în „numele proprietăților calculate”. De exemplu, acesta se compilează perfect în toate browserele care suportă sintaxa:

var foo = {
    [`bar` + 1]: `baz`
};

și creează obiectul {"bar1": "baz"}.

De ce nu sunt permise șirurile template ca chei literale ale obiectelor? Este din motive de performanță? Șirurile template trebuie compilate, posibil la rulare (corectează-mă dacă greșesc), ceea ce înseamnă că de fiecare dată când interpretorul întâlnește acest obiect, va trebui să calculeze numele obiectului. Luând în considerare lucruri precum șirurile template „gătite”, se pare că acest lucru ar putea încetini lucrurile, deși avem getter-e și setter-e încă din ES5. Firefox nu menționează aceasta ca o eroare, motiv pentru care am găsit acest lucru neașteptat. Va fi permisă această sintaxă în viitor?

Răspuns #1

De ce nu sunt permise șirurile șablon ca chei literale ale obiectelor?

Șirurile de tip șablon sunt expresii, nu constante literale1. Poți folosi numai constante literale de șir (și identificatori) pentru numele proprietăților, pentru orice altceva - care nu se știe că este static - ai nevoie de un nume de proprietate calculat.

Este din motive de performanță?

Nu, asta este puțin probabil. Este pentru a ușura analizarea, și face ușor să distingi numele proprietăților constante (cunoscute static) de cele calculate dinamic.

Și mai ales, este o funcție de care nimeni nu are nevoie. Nu simplifică sau scurtează nimic, iar ceea ce ai realiza cu ea este deja posibil.

Va fi permisă sintaxa la un moment dat în viitor?

Nu.

1: Chiar și atunci când sunt numite „literals de tip șablon”, tehnic vorbind ele nu sunt literali. Și: șabloanele nici măcar nu trebuie să fie șiruri de caractere, ele pot evalua la orice.

Răspunsul #2

Se așteaptă ca cheile obiectului să fie șiruri de caractere:

let obj1 = { name: "Alex", age: "28"} // this is a 'normal' style

Dacă expresia oferită ca și cheie nu este un șir de caractere, motorul va încerca să o forțeze într-un șir de caractere.

let obj2 = { 5: "Banana", 10: "Apple" } // e.g. number key is coersed into string

Șirurile template trebuie evaluate mai întâi. Prin urmare, nu sunt „convertibile”. Drept urmare, motorul aruncă o eroare, deoarece încearcă să le convertească (exemplu 1)

Pe de altă parte, tablourile sunt în mod natural convertibile în șiruri de caractere, prin urmare pot fi folosite ca chei complet legale

În plus, tablourile care conțin șiruri template pot fi folosite ca chei perfect legale atunci când se creează un obiect, deoarece motorul evaluează mai întâi expresia template, apoi convertește tabloul într-un șir (exemplul 2)

vezi exemple:

    /* example 1 */ {`foo`: "bar"}   // Error: template strs aren't coersible

Pentru a putea folosi un șir șablon ca și cheie a unui obiect, pur și simplu înfășoară-l ca element unic al unui array:

    /* example 2 */ {[`foo`]: "bar"} /* OK: {foo: "bar"}, the internal `foo` 
                                           template is first resolved to a native 
                                           "foo" string, resulting in array ["foo"],
                                           which then coersed to the "foo" key.*/
    
    /* example 3 */ const obj = {foo: "bar"}
                        const obj1 = {[obj.foo]: "bar"} // OK: {bar: "bar"} !!

Răspunsul #3

Postez acest răspuns pentru a evidenția comentariul foarte apreciat al lui @Bergi la un răspuns. Dacă vrei să folosești o valoare dinamică dintr-o variabilă ca și cheie a obiectului tău în literalul de obiect, folosește pur și simplu o proprietate calculată:

const dynamicKey = someCondition ? 'someKeyName' : 'otherKeyName';
const obj = {[dynamicKey]: val};

Ai putea să scrii asta și astfel:

const obj = {[`${dynamicKey}`]: val};