Un fatto "divertente" di JS __proto__

Nov 26 2022
Se mi hai seguito abbastanza a lungo, sai già quanto sono sempre stato contrario a __proto__ eppure, da quando è arrivato allo standard ECMAScript molto tempo fa, ci sono ancora rare occasioni in cui trovo almeno il suo utilizzo per marchiare un oggetto accettabile: mettendo da parte le prestazioni, e tieni presente che non sto suggerendo affatto l'uso di __proto__ in natura, questo post esiste per altri motivi. Oggetto.
Foto di Mark Williams su Unsplash

Se mi hai seguito abbastanza a lungo, sai già quanto __proto__sono sempre stato contrario eppure, da quando è arrivato allo standard ECMAScript molto tempo fa, ci sono ancora rare occasioni in cui trovo accettabile almeno il suo utilizzo per marchiare un oggetto :

const factory = (fields, {prototype} = Object) => ({
  __proto__: prototype,
  ...fields
});

// mimic an <a /> reference
factory({href: '/'}, HTMLAnchorElement);

In Firefox, __proto__ ha un punteggio migliore rispetto a new Class

Mettendo da parte le prestazioni, e tieni presente che non sto suggerendo affatto l'uso di __proto__in natura, questo post esiste per altri motivi.

Oggetto.prototipo.__proto__

Sono abbastanza sicuro che tutti sappiano cosa fa l'accessor __proto__ , quindi vorrei proporti una sfida ... e sì, questo è tutto JS valido:

class Test {}
const __proto__ = Test.prototype;

// what do these operations return?
({__proto__} instanceof Test);
({__proto__: __proto__} instanceof Test);
({"__proto__": __proto__} instanceof Test);
({["__proto__"]: __proto__} instanceof Test);

// what do these operations return?
({__proto__}.__proto__ === Test.prototype);
({__proto__: __proto__}.__proto__ === Test.prototype);
({"__proto__": __proto__}.__proto__ === Test.prototype);
({["__proto__"]: __proto__}.__proto__ === Test.prototype);

Se non hai eseguito tu stesso questi frammenti per conoscere la risposta, posso aiutarti! Nella prima sfida, l'output sarà false, true, truee falseancora, e il motivo è che entrambi {__proto__}e {["__proto__"]}sono definiti come proprie proprietà , mentre l'assegnamento tramite sintassi, senza utilizzare particolari caratteristiche sintattiche, anche con virgolette in giro, passa effettivamente attraverso l' Object.prototype.__proto__accessor.

D'altra parte, nella seconda sfida (all true) non importa se accediamo __proto__direttamente o as ["__proto__"], quindi praticamente non c'è simmetria zero nel modo in cui possiamo attivare il __proto__setter, dal modo in cui possiamo attivare il __proto__getter una volta o è una proprietà propria o una magica porta ereditaria.

…e non solo __proto__

Non ho controllato me stesso, ma credo che ogni __xxx__accessorio speciale legacy soffra della stessa __proto__maledizione, quindi fai attenzione là fuori mescolando l'ultima fantastica sintassi JS per assegnare proprietà con il tuo intento e le tue aspettative reali, poiché le cose potrebbero facilmente andare banane se provi a farlo sii intelligente nell'assegnare queste proprietà .

E questo è tutto gente!

L'unico take away da questo post è probabilmente riassunto come tale:

  • non utilizzare parti del linguaggio legacy ancora funzionanti, se desideri evitare sorprese oggi o domani, su come si comportano con la nuova sintassi
  • preferire esplicito (e sfortunatamente più lento) Object.setPrototypeOfogni volta che è strettamente necessario impostare manualmente il prototipo di un oggetto, ma utilizzare le classi in ogni altro caso ogni volta che è possibile
  • cancella dalla tua memoria questo post o rimpiccioliscilo in una breve frase come: " Non dovrei mai usare __proto__nel mio codice " e vai avanti imparando cose nuove e fantasiose che non incasinano il tuo cervello o i tuoi sentimenti