Lietuvių

Išnagrinėkite JavaScript simbolius: jų paskirtį, kūrimą, taikymą unikaliems savybių raktams, metaduomenų saugojimui ir vardų konfliktų prevencijai. Pateikti praktiniai pavyzdžiai.

JavaScript simboliai: unikalūs savybių raktai ir metaduomenys

JavaScript simboliai, pristatyti ECMAScript 2015 (ES6), suteikia mechanizmą unikaliems ir nekintamiems savybių raktams kurti. Skirtingai nuo eilučių ar skaičių, simboliai garantuotai yra unikalūs visoje jūsų JavaScript programoje. Jie suteikia būdą išvengti vardų konfliktų, prijungti metaduomenis prie objektų, netrukdant esamoms savybėms, ir pritaikyti objektų elgseną. Šiame straipsnyje pateikiama išsami JavaScript simbolių apžvalga, apimanti jų kūrimą, taikymą ir geriausias praktikas.

Kas yra JavaScript simboliai?

Simbolis yra primityvus duomenų tipas JavaScript, panašus į skaičius, eilutes, logines reikšmes, null ir undefined. Tačiau, skirtingai nuo kitų primityvių tipų, simboliai yra unikalūs. Kiekvieną kartą sukūrę simbolį, gaunate visiškai naują, unikalią reikšmę. Dėl šio unikalumo simboliai idealiai tinka:

Simbolių kūrimas

Simbolį sukuriate naudodami Symbol() konstruktorių. Svarbu pažymėti, kad negalite naudoti new Symbol(); simboliai nėra objektai, o primityvios reikšmės.

Pagrindinis simbolių kūrimas

Paprasčiausias būdas sukurti simbolį yra:

const mySymbol = Symbol();
console.log(typeof mySymbol); // Išvestis: symbol

Kiekvienas Symbol() iškvietimas sugeneruoja naują, unikalią reikšmę:

const symbol1 = Symbol();
const symbol2 = Symbol();
console.log(symbol1 === symbol2); // Išvestis: false

Simbolių aprašymai

Kurdami simbolį, galite pateikti neprivalomą eilutės aprašymą. Šis aprašymas naudingas derinant ir registruojant, tačiau jis neturi įtakos simbolio unikalumui.

const mySymbol = Symbol("myDescription");
console.log(mySymbol.toString()); // Išvestis: Symbol(myDescription)

Aprašymas skirtas tik informaciniams tikslams; du simboliai su tuo pačiu aprašymu vis tiek yra unikalūs:

const symbolA = Symbol("same description");
const symbolB = Symbol("same description");
console.log(symbolA === symbolB); // Išvestis: false

Simbolių naudojimas kaip savybių raktai

Simboliai yra ypač naudingi kaip savybių raktai, nes jie garantuoja unikalumą, užkertant kelią vardų konfliktams pridedant savybes prie objektų.

Simbolių savybių pridėjimas

Simbolius galite naudoti kaip savybių raktus, lygiai taip pat kaip eilutes ar skaičius:

const mySymbol = Symbol("myKey");
const myObject = {};

myObject[mySymbol] = "Hello, Symbol!";

console.log(myObject[mySymbol]); // Išvestis: Hello, Symbol!

Vardų konfliktų vengimas

Įsivaizduokite, kad dirbate su trečiosios šalies biblioteka, kuri prideda savybes prie objektų. Galbūt norėsite pridėti savo savybes, nerizikuodami perrašyti esamų. Simboliai suteikia saugų būdą tai padaryti:

// Trečiosios šalies biblioteka (imituota)
const libraryObject = {
  name: "Library Object",
  version: "1.0"
};

// Jūsų kodas
const mySecretKey = Symbol("mySecret");
libraryObject[mySecretKey] = "Top Secret Information";

console.log(libraryObject.name); // Išvestis: Library Object
console.log(libraryObject[mySecretKey]); // Išvestis: Top Secret Information

Šiame pavyzdyje mySecretKey užtikrina, kad jūsų savybė nesikirs su jokiomis esamomis savybėmis libraryObject objekte.

Simbolių savybių išvardijimas

Viena iš esminių simbolių savybių ypatybių yra ta, kad jos yra paslėptos nuo standartinių išvardijimo metodų, tokių kaip for...in ciklai ir Object.keys(). Tai padeda apsaugoti objektų vientisumą ir apsaugo nuo atsitiktinės prieigos prie simbolių savybių ar jų modifikavimo.

const mySymbol = Symbol("myKey");
const myObject = {
  name: "My Object",
  [mySymbol]: "Symbol Value"
};

console.log(Object.keys(myObject)); // Išvestis: ["name"]

for (let key in myObject) {
  console.log(key); // Išvestis: name
}

Norėdami pasiekti simbolių savybes, turite naudoti Object.getOwnPropertySymbols(), kuris grąžina visų objekto simbolių savybių masyvą:

const mySymbol = Symbol("myKey");
const myObject = {
  name: "My Object",
  [mySymbol]: "Symbol Value"
};

const symbolKeys = Object.getOwnPropertySymbols(myObject);
console.log(symbolKeys); // Išvestis: [Symbol(myKey)]
console.log(myObject[symbolKeys[0]]); // Išvestis: Symbol Value

Gerai žinomi simboliai

JavaScript pateikia įtaisytųjų simbolių rinkinį, žinomą kaip gerai žinomus simbolius, kurie atspindi specifinę elgseną ar funkcionalumą. Šie simboliai yra Symbol konstruktoriaus savybės (pvz., Symbol.iterator, Symbol.toStringTag). Jie leidžia jums pritaikyti, kaip objektai elgiasi įvairiuose kontekstuose.

Symbol.iterator

Symbol.iterator yra simbolis, kuris apibrėžia numatytąjį objekto iteratorių. Kai objektas turi metodą su raktu Symbol.iterator, jis tampa iteruojamas, o tai reiškia, kad galite jį naudoti su for...of ciklais ir skleidimo operatoriumi (...).

Pavyzdys: individualaus iteruojamo objekto kūrimas

const myCollection = {
  items: [1, 2, 3, 4, 5],
  [Symbol.iterator]: function* () {
    for (let item of this.items) {
      yield item;
    }
  }
};

for (let item of myCollection) {
  console.log(item); // Išvestis: 1, 2, 3, 4, 5
}

console.log([...myCollection]); // Išvestis: [1, 2, 3, 4, 5]

Šiame pavyzdyje myCollection yra objektas, kuris įgyvendina iteratoriaus protokolą naudodamas Symbol.iterator. Generatoriaus funkcija grąžina (yields) kiekvieną elementą iš items masyvo, paversdama myCollection iteruojamu.

Symbol.toStringTag

Symbol.toStringTag yra simbolis, leidžiantis pritaikyti objekto eilutės reprezentaciją, kai iškviečiamas Object.prototype.toString().

Pavyzdys: toString() reprezentacijos pritaikymas

class MyClass {
  get [Symbol.toStringTag]() {
    return 'MyClassInstance';
  }
}

const instance = new MyClass();
console.log(Object.prototype.toString.call(instance)); // Išvestis: [object MyClassInstance]

Be Symbol.toStringTag, išvestis būtų [object Object]. Šis simbolis suteikia būdą pateikti labiau aprašomąją jūsų objektų eilutės reprezentaciją.

Symbol.hasInstance

Symbol.hasInstance yra simbolis, leidžiantis pritaikyti instanceof operatoriaus elgseną. Paprastai instanceof patikrina, ar objekto prototipų grandinėje yra konstruktoriaus prototype savybė. Symbol.hasInstance leidžia pakeisti šią elgseną.

Pavyzdys: instanceof patikrinimo pritaikymas

class MyClass {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance);
  }
}

console.log([] instanceof MyClass); // Išvestis: true
console.log({} instanceof MyClass); // Išvestis: false

Šiame pavyzdyje Symbol.hasInstance metodas patikrina, ar egzempliorius yra masyvas. Tai efektyviai paverčia MyClass veikiančiu kaip masyvų patikrinimas, nepriklausomai nuo tikrosios prototipų grandinės.

Kiti gerai žinomi simboliai

JavaScript apibrėžia keletą kitų gerai žinomų simbolių, įskaitant:

Globalus simbolių registras

Kartais reikia dalintis simboliais tarp skirtingų programos dalių ar net tarp skirtingų programų. Globalus simbolių registras suteikia mechanizmą registruoti ir gauti simbolius pagal raktą.

Symbol.for(key)

Metodas Symbol.for(key) patikrina, ar globaliame registre egzistuoja simbolis su nurodytu raktu. Jei jis egzistuoja, metodas grąžina tą simbolį. Jei neegzistuoja, jis sukuria naują simbolį su raktu ir užregistruoja jį registre.

const globalSymbol1 = Symbol.for("myGlobalSymbol");
const globalSymbol2 = Symbol.for("myGlobalSymbol");

console.log(globalSymbol1 === globalSymbol2); // Išvestis: true
console.log(Symbol.keyFor(globalSymbol1)); // Išvestis: myGlobalSymbol

Symbol.keyFor(symbol)

Metodas Symbol.keyFor(symbol) grąžina raktą, susietą su simboliu globaliame registre. Jei simbolis nėra registre, jis grąžina undefined.

const mySymbol = Symbol("localSymbol");
console.log(Symbol.keyFor(mySymbol)); // Išvestis: undefined

const globalSymbol = Symbol.for("myGlobalSymbol");
console.log(Symbol.keyFor(globalSymbol)); // Išvestis: myGlobalSymbol

Svarbu: simboliai, sukurti naudojant Symbol(), *nėra* automatiškai registruojami globaliame registre. Tik simboliai, sukurti (arba gauti) naudojant Symbol.for(), yra registro dalis.

Praktiniai pavyzdžiai ir naudojimo atvejai

Štai keletas praktinių pavyzdžių, parodančių, kaip simbolius galima naudoti realaus pasaulio scenarijuose:

1. Įskiepių sistemų kūrimas

Simboliai gali būti naudojami kuriant įskiepių sistemas, kuriose skirtingi moduliai gali išplėsti pagrindinio objekto funkcionalumą, nesukeldami konfliktų su vienas kito savybėmis.

// Pagrindinis objektas
const coreObject = {
  name: "Core Object",
  version: "1.0"
};

// Įskiepis 1
const plugin1Key = Symbol("plugin1");
coreObject[plugin1Key] = {
  description: "Plugin 1 adds extra functionality",
  activate: function() {
    console.log("Plugin 1 activated");
  }
};

// Įskiepis 2
const plugin2Key = Symbol("plugin2");
coreObject[plugin2Key] = {
  author: "Another Developer",
  init: function() {
    console.log("Plugin 2 initialized");
  }
};

// Prieiga prie įskiepių
console.log(coreObject[plugin1Key].description); // Išvestis: Plugin 1 adds extra functionality
coreObject[plugin2Key].init(); // Išvestis: Plugin 2 initialized

Šiame pavyzdyje kiekvienas įskiepis naudoja unikalų simbolio raktą, užkertant kelią galimiems vardų konfliktams ir užtikrinant, kad įskiepiai galėtų taikiai egzistuoti kartu.

2. Metaduomenų pridėjimas prie DOM elementų

Simboliai gali būti naudojami metaduomenims prie DOM elementų pridėti, netrukdant jų esamiems atributams ar savybėms.

const element = document.createElement("div");

const dataKey = Symbol("elementData");
element[dataKey] = {
  type: "widget",
  config: {},
  timestamp: Date.now()
};

// Prieiga prie metaduomenų
console.log(element[dataKey].type); // Išvestis: widget

Šis metodas išlaiko metaduomenis atskirai nuo standartinių elemento atributų, pagerina palaikomumą ir išvengia galimų konfliktų su CSS ar kitu JavaScript kodu.

3. Privačių savybių įgyvendinimas

Nors JavaScript neturi tikrų privačių savybių, simboliai gali būti naudojami privatumui imituoti. Naudodami simbolį kaip savybės raktą, galite apsunkinti (bet ne padaryti neįmanomą) išoriniam kodui prieigą prie savybės.

class MyClass {
  #privateSymbol = Symbol("privateData"); // Pastaba: ši '#' sintaksė yra *tikras* privatus laukas, pristatytas ES2020, kitoks nei pavyzdyje

  constructor(data) {
    this[this.#privateSymbol] = data;
  }

  getData() {
    return this[this.#privateSymbol];
  }
}

const myInstance = new MyClass("Sensitive Information");
console.log(myInstance.getData()); // Išvestis: Sensitive Information

// Prieiga prie „privačios“ savybės (sudėtinga, bet įmanoma)
const symbolKeys = Object.getOwnPropertySymbols(myInstance);
console.log(myInstance[symbolKeys[0]]); // Išvestis: Sensitive Information

Nors Object.getOwnPropertySymbols() vis dar gali atskleisti simbolį, tai sumažina tikimybę, kad išorinis kodas netyčia pasieks ar modifikuos „privačią“ savybę. Pastaba: tikri privatūs laukai (naudojant „#“ priešdėlį) dabar yra prieinami šiuolaikiniame JavaScript ir siūlo stipresnes privatumo garantijas.

Geriausios simbolių naudojimo praktikos

Štai keletas geriausių praktikų, kurių reikėtų nepamiršti dirbant su simboliais:

Išvada

JavaScript simboliai siūlo galingą mechanizmą unikaliems savybių raktams kurti, metaduomenims prie objektų pridėti ir objektų elgsenai pritaikyti. Suprasdami, kaip veikia simboliai, ir laikydamiesi geriausių praktikų, galite rašyti tvirtesnį, lengviau prižiūrimą ir be konfliktų veikiantį JavaScript kodą. Nesvarbu, ar kuriate įskiepių sistemas, pridedate metaduomenis prie DOM elementų, ar imituojate privačias savybes, simboliai yra vertingas įrankis, gerinantis jūsų JavaScript kūrimo procesą.