JavaScriptové perličky VI.

Malý kvíz: Co vypíše následující skript na posledním řádku?

x = new Object();
x.vlastnost = 0;
y = x;
x.vlastnost = 10;
document.write(y.vlastnost);

Správná odpověď je "10". Přiřazení na třetím řádku totiž neznamená zkopírování objektů, ale jen přiřazení reference na objekt. Nejlepší je si objekty v JavaScriptu představovat jako ukazatele na objekty třeba v C++ – z tohoto pohledu pak třetí řádek říká, že x a y ukazují na tentýž objekt. Když pak změníme hodnotu vlastnosti vlastnost u jednoho, musí se změnit i u druhého.

Chování operátoru přiřazení je ve většině případů rozumné, ale občas potřebujeme objekt doopravdy zkopírovat. JavaScript samotný to neumí (nebo o tom aspoň nevím), takže si tuto funkci budeme muset zařídit sami. Přidáme proto do prototypu třídy Object metodu clone, která jako svou návratovou hodnotu vydá kopii objektu, ve kterém byla zavolána.

Dnes si ukážeme první způsob, jak ji naprogramovat. Spočívá ve využití metody Obejct.toSource, která vrátí řetězec reprezentující zápis objektu v JavaScriptu. Tento řetězec pak vyhodnotíme globální funkcí eval – výsledkem bude instance objektu vytvořená podle řetězce a tedy shodná s předchozím objektem. Zde je kód:

Object.prototype.clone = function() {
  return eval(this.toSource());
}

Tato metoda není zrovna čistá (metoda toSource je míněna spíše jako interní), navíc selhává v případech, kdy objekt vytvoříme konstruktorem a pak do něj přiřadíme nějaké vlastnosti. Například v následujícím kódu se na posledním řádku vypíše undefined, protože toSource vrátí řetězec "({y:5})" a nastavení vlastnosti x v prototypu jaksi pomine (proč, tomu přesně nerozumím).

function Trida() {};
Trida.prototype = { x: 1 };

a = new Trida();
a.y = 5;
b = a.clone();
document.write(b.x);

Z tohoto důvodu příště zkusíme metodu clone naprogramovat jinou cestou.