Autor Zpráva
dejvik
Profil *
Zdravím,

zkouším si v konzoli hledat odpověď na instanceof, ale bez instanceof:)
Př:
//mám funkci:
function A() {};
a = new A;
a instanceof A; //vrátí true
a instanceof Object; //vrátí true


Poslední dva příkazy bych chtěl nahradit jiným postupem, který mi ukáže, jak vlastně instanceof funguje. Instanceof chápu tak, že se podívá do všech prototypů daného objektu. Tzn: a.constructor.prototype, a.constructor.prototype.constructor.prototype, atd. Každý prototype nějak porovná s funkcí A a vrátí true, jestli je alespoň jedno porovnání true, jinak vrátí false. Tímto způsobem bych se měl dostat nějak k funkci/prototypu Object, ale nedaří se mi to.

Např zde mi to funguje:
a instanceof A; //vrátí true
a.constructor.prototype == A.prototype


Ale u:
a instanceof Object; //vrátí true
a.constructor.prototype // A {}
a.constructor.prototype.constructor.prototype // A {}
se zase nemůžu dostat k Object.


Na https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special/instanceof se píše of instanceof: The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.
Nějak té formulaci přesně nerozumím.

Teď jsem ještě zkusil __proto__ a chová se k mému překvapení jinak než constructor.prototype :/
Už jsem na to asi přišel:
a.__proto__ == A.prototype // jako a instanceof A; 
a.__proto__.__proto__ == Object.prototype // jako a instanceof Object

Takže instanceof asi prochází prototype chain objektu přes __proto__ a ne přes constructor.prototype, jak jsem si dosud myslel.

Není __proto__ nestandardní a nemělo by se používat? Něco vhodnějšího není?

A záhada nakonec:
A.prototype.constructor; // je A()
//teď A.prototype.constructor změníme:
function B() {};
A.prototype.constructor = B;
a instanceof A; // je stále true

Je a.__proto__ jen reference na A.prototype?
Witiko
Profil
dejvik:
Tady je nepořádek v tom, že tradičně je jediný způsob vytvoření prototypu přes funkce, což je mírně matoucí a ruce svazující přístup k prototypální dědičnosti. Pravda je taková, že hodnota Funkce.prototype.constructor se dá měnit a to, že odkazuje zpětně na Funkce není zaručeno (je možné ji i smazat). K objektům je neviditelně přilepen objekt odkazující defaultně na Object.prototype, který nazývejme například [[Prototype]] jako specifikace nebo __proto__ podle nestandardní vlastnosti od Mozilly. [[Prototype]] nemá co dělat s prototype objektem na funkcích. prototype na funkcích pouze determinuje, jaký [[Prototype]] budou mít instance funkce. Nicméně je možné tvořit i objekty, jejichž [[Prototype]] není přebráno z žádné funkce a atribut constructor bychom v nich hledali marně, protože konstruktorovou metodu postrádají. (To již částečně nabízí ECMA5 metoda Object.create)

Není __proto__ nestandardní a nemělo by se používat? Něco vhodnějšího není?
ECMA5 definuje standardní metody Object.getPrototypeOf a Object.prototype.isPrototypeOf. Problém, který s těmito metodami mám je, že na rozdíl od __proto__ nedovolují do [[Prototype]] přiřazovat jiný objekt, pouze kontrolovat či měnit ten stávající. __proto__ je velmi praktický nástroj, který umožňuje při zachování přehledného zápisu volnou definici prototypů bez závislosti na modelu třída - instance:
var a = {a:"1"},
    b = {b:"2"},
    c = {c:"3"};
a.__proto__ = b;
b.__proto__ = c;
a.a + a.b + a.c; // 123
Problém s __proto__ tkví v tom, že znemožňuje definici atributu jménem __proto__ na jakémkoliv objektu, což prostě není fajn. Ostatní předdefinované ukusovače prototype jmenného prostoru jde alespoň "přepsat" lokálním atributem objektu, __proto__ ale není prostý atribut nýbrž accessor a při přiřazení hodnoty tedy dojde pouze k zavolání setter metody namísto nahrazení obsahu atributu. Navíc se nejedná o prostý zděděný objekt v tom smyslu, že bychom ho nalezli na Object.prototype.prototype, __proto__ totiž musí být na straně interpreta kódu generováno a lepeno na každý objekt extra (({}).__proto__ !== Object.prototype.__proto__), což má zajímavé výsledky:
var a = {};
a.hasOwnProperty("isPrototypeOf"); // false
a.isPrototypeOf = 123;
a.isPrototypeOf === 123; // true
a.isPrototypeOf !== a.__proto__.isPrototypeOf; // true
a.hasOwnProperty("isPrototypeOf"); // true
Object.getOwnPropertyDescriptor(a,"isPrototypeOf"); // {configurable: true, enumerable: true, value: 123, writable: true}

Ale:

var a = {};
a.hasOwnProperty("__proto__"); // true
Object.getOwnPropertyDescriptor(a,"__proto__"); // undefined
delete a.__proto__; // false
a.__proto__ = 123;
a.__proto__ === 123; // false
Řešení bych viděl v zavedení klíčového slova / syntaktické změně.

Co se týče tvé záhady na konec - javascript kontroluje [[Prototype]] objekt jako takový bez jakéhokoliv ohledu na constructor. Dalo by se říct, že a instanceof A provede tento test: a.__proto__ === A.prototype („Je a.__proto__ jen reference na A.prototype?“ - Ano). To je samozřejmě zjednodušené, ve skutečnosti funkce projde celým případným [[Prototype]] řetězcem (a.__proto__.__proto__.__proto__ ...) dokud nedojde k null a otestuje jej proti prototype zadané funkce. -> Řekl bych, že jsem ti právě česky přeformuloval to „The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.

Napsal jsem ti instanceOf funkci, která pracuje identicky s instanceof klíčovým slovem a měla by pomoct s pochopením:
function instanceOf(instance, třída) {
  var instanceProto = instance,
      třídaProto = třída.prototype;
  while(instanceProto = instanceProto.__proto__) {
    if(instanceProto === třídaProto) return true;
  } return false;
};

function a() {};
function b() {};
b.prototype = new a;
function c() {};
c.prototype = new b;

var d = new c;
instanceOf(d, c); // true
instanceOf(d, b); // true
instanceOf(d, a); // true
instanceOf(d, Object); // true

Verze konformní se standardy by pak byla:
if(!(Object.getPrototypeOf instanceof Function) && "__proto__" in {})
  Object.getPrototypeOf = function(object) {
    return object.__proto__;
  };

function instanceOf(instance, třída) {
  if(!(třída instanceof Function))
    throw new TypeError("Expecting a function in instanceof check, but got #<" + typeof třída + ">");
  var instanceProto = instance,
      třídaProto = třída.prototype;
  while(instanceProto = Object.getPrototypeOf(instanceProto)) {
    if(instanceProto === třídaProto) return true;
  } return false;
};
dejvik
Profil *
Omlouvám se za prodlevu.
Witiko:
Pravda je taková, že hodnota Funkce.prototype.constructor se dá měnit a to, že odkazuje zpětně na Funkce není zaručeno (je možné ji i smazat).
> Co se týče tvé záhady na konec - javascript kontroluje [[Prototype]] objekt jako takový bez jakéhokoliv ohledu na constructor.
Říkal jsem si, že se chová divně. Teď ale nechápu, proč tam je teda atribut (jestli se to dá vůbec nazvat) constructor, když ho ani v té tvojí instanceOf nepoužijeme?
Na Object Oriented Programming in JavaScript by Mike Koss sekce Defining a Sub-Class se používá constructor u napodobování zjednodušeného objektového paradigmatu prototypovým. Nicméně vypustím-li řádek:
B.prototype.constructor = B;

Výstup se nezmění.
Při definici funkce se tato definovaná funkce vloží do jejího prototype.constructor. Jenže když ten prototype můžeme kdykoli přepsat a dělá se to zřejmě poměrně často, nevím k čemu constructor je.

K objektům je neviditelně přilepen objekt odkazující defaultně na Object.prototype, který nazývejme například [[Prototype]] jako specifikace nebo __proto__ podle nestandardní vlastnosti od Mozilly. [[Prototype]] nemá co dělat s prototype objektem na funkcích. prototype na funkcích pouze determinuje, jaký [[Prototype]] budou mít instance funkce. Nicméně je možné tvořit i objekty, jejichž [[Prototype]] není přebráno z žádné funkce a atribut constructor bychom v nich hledali marně, protože konstruktorovou metodu postrádají. (To již částečně nabízí ECMA5 metoda Object.create)
...
__proto__ je velmi praktický nástroj, který umožňuje při zachování přehledného zápisu volnou definici prototypů bez závislosti na modelu třída - instance:

Rozumím. Při volání new se předá reference prototype funkce novému objektu do pseudo atributu __proto__. A dál si s tím můžeme dělat, co chceme. Nějak mě děsí _proto__ podle nestandardní vlastnosti od Mozilly. Je __proto__ podporované v ostatních prohlížečích? V Chrome ano.

Problém s __proto__ tkví v tom, že znemožňuje definici atributu jménem __proto__ na jakémkoliv objektu, což prostě není fajn. Ostatní předdefinované ukusovače prototype jmenného prostoru jde alespoň "přepsat" lokálním atributem objektu,
Dejme tomu, že objekt a má v [[Prototype]] atribut atr == "cau". Potom když budu chtít měnit atribut atr na objektu a (a.atr = "ahoj"), vytvoří se jen lokální proměnná atr. Tedy a.__proto__.atr bude stále "cau". Tohle ale s __proto__ neumíme. Je tak?

> __proto__ ale není prostý atribut nýbrž accessor a při přiřazení hodnoty tedy dojde pouze k zavolání setter metody namísto nahrazení obsahu atributu. Navíc se nejedná o prostý zděděný objekt v tom smyslu, že bychom ho nalezli na Object.prototype.prototype, __proto__ totiž musí být na straně interpreta kódu generováno a lepeno na každý objekt extra (({}).__proto__ !== Object.prototype.__proto__), což má zajímavé výsledky:
Object.prototype.prototype, __proto__ bude asi překlep.

var a = {};
a.hasOwnProperty("__proto__"); // true
Object.getOwnPropertyDescriptor(a,"__proto__"); // undefined
delete a.__proto__; // false
a.__proto__ = 123;
a.__proto__ === 123; // false
Řešení bych viděl v zavedení klíčového slova / syntaktické změně.

To je děsivé. A navíc to není v
for(item in a)

Budu si dávat na __proto__ pozor:)

Zkusil jsem tu instanceOf a funguje, jak by měla. Takhle jsem si to nějak představoval. Kromě jiného jsem si nevědel rady s tím constructorem.

if(!(Object.getPrototypeOf instanceof Function) && "__proto__" in {})
Object.getPrototypeOf = function(object) {
return object.__proto__;
};

Tenhle kód mě trochu zmátl, ale implementuje v podstatě funkci getPrototypeOf na objektu/funkci Objekt.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0