Autor Zpráva
Joker
Profil
Přemýšlím nad následujícím zápisem:
var myNS = {
  Foo : function() {
    this.hello = function () { alert("Ahoj!"); };
  } 
  , Bar : function() {
    var obj = new myNS.Foo();
    obj.bye = function() { alert("Tak zatím!"); };
    return obj;
  }
};

var test = new myNS.Bar();
test.hello();
test.bye();

Objekt Bar vlastně dědí od objektu Foo tím způsobem, že v konstruktoru vyrobí objekt Foo, rozšíří ho o další vlastnosti a ten výsledek vrátí jako sebe.

A ptám se větších expertů na OOP v JavaScriptu, než jsem já: Je to dobrý, nebo špatný přístup?
Radek9
Profil
Joker:
Ona tohle technicky vzato dědičnost není, pořád to je objekt, který přímo dědí z Foo.prototype. (Tedy test instanceof myNS.Bar bude false.) Je to jen jakýsi obal kolem konstruktoru. Nicméně se nedá říct, že je to špatný způsob. Mnohdy to úplně stačí a je to nejjednodušší řešení. Za předpokladu, že bys ale chtěl skutečnou dědičnost, se to řeší přes zdědění prototypu:

function Foo() {
  // …
}

Foo.prototype.hello = function () { alert("Ahoj!"); };

function Bar() {
  // …
}

Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.constructor = Bar;

Bar.prototype.bye = function () { alert("Tak zatím!"); };

var test = new Bar();
test.hello();
test.bye();

test instanceof Foo; // true
test instanceof Bar; // true

Tohle řešení má navíc výhodu v tom, že reaguje i na pozdější změny obou prototypů:

test.prop; // undefined

Foo.prototype.prop = 1;
test.prop; // 1

Bar.prototype.prop = 2;
test.prop; // 2
1Pupik1989
Profil
Je to špatný způsob. Vytvoříš totiž objekt, který se rázem zahodí, protože nemá využití, jelikož z konstruktoru vracíš jiný objekt. Když zavoláš jen new Bar, tak dostaneš stejný výsledek. Já dědičnost píšu trochu jiným stylem.

Bar.prototype = (function(){
function F(){};
F.prototype = Foo.prototype;
return new F; 
}();;

Promiň, píšu to z telefonu, ale snad je princip jasný.
Radek9
Profil
1Pupik1989:
Je to špatný způsob. Vytvoříš totiž objekt, který se rázem zahodí
To dnešním enginům nedělá zas takový problém. Vytvořit prázdný objekt zabere opravdu jen málo výpočetního času. V aplikaci se ti beztak válí hromada nepotřebných objektů, o které se časem postará garabage collector.

Ale rozhodně bych neřekl, že je to špatný způsob. Jedná-li se o drobné rozšíření, u kterého nehrozí, že by se muselo při běhu aplikace rozšiřovat, tak je to naprosto v pořádku.
_es
Profil
Joker:
Nevýhodou je, že pre každý objekt sa vytvárajú odlišné objekty funkcií pre obe metódy aj hellou aj bye.
1Pupik1989
Profil
Radek9:
Je to zbytečný zlozvyk. Hlavně nikde se nic nedědí. Další nevýhodou je, že při každém vytvoření objektu se znovu definují metody.

var myNS = {
  Foo:function(){},
  Bar:function(){}
};

myNS.Foo.prototype.hello = function(){ alert('Ahoj'); };

myNS.Bar.prototype = (function(){
  function F(){};
  F.prototype = myNS.Foo.prototype;
  return new F;
})();

myNS.Bar.prototype.bye = function(){ alert('Tak zatím!'); };


var test = new myNS.Bar();
test.hello();
test.bye();

test instanceof myNS.Bar;      //true
test instanceof myNS.Foo;      //true

Ve výkonu je to hodně znatelné. http://jsperf.com/constructors-djpw
Radek9
Profil
_es, 1Pupik1989:
pre každý objekt sa vytvárajú odlišné objekty funkcií pre obe metódy
při každém vytvoření objektu se znovu definují metody.
Což zase až tak nevadí, v některých případech je to dokonce rychlejší. A zrovna tohle jde vyřešit tak, že se metoda definuje zvlášť a k objektu se přiřadí její reference.

function bye() { alert("Tak zatím!"); }

function Bar() {
  var obj = new Foo();
  obj.bye = bye;
  return obj;
}

1Pupik1989:
Je to zbytečný zlozvyk. Hlavně nikde se nic nedědí.
Už jsem uváděl, že to dědičnost ve skutečnosti není. Ale rozhodně bych to neoznačil za zlozvyk. V JS je přehršel návrhových vzorů a nedá se jednoznačně říct, který je nejlepší. Vždy záleží na situaci, v mnoha případech je dědičnost naprosto zbytečná.
Joker
Profil
Díky za komentáře a za tu myšlenku s testem rychlosti.
Zkoušel jsem to a dost se to liší podle prohlížeče. U Webkitů (Chrome a spol.) je zdá se rychlejší closure. Ve staré Opeře je naopak rychlejší spíš použití prototypu (přičemž v některých testech byl prototyp ve staré Opeře rychlejší, než jakákoliv varianta v novém prohlížeči) a v IE 10 to vychází podobně.

Ještě přidám další poznatky ohledně výkonu: Varianta, se na nový objekt věší předem připravené funkce (closure 2) vychází konzistentně jako nejpomalejší (trochu překvapivě, řekl bych, ale dost podstatně, většinou o řád pomalejší). Při vytváření konzistentně (a asi logicky) vítězí prototyp, práce s objektem závisí na prohlížeči. A IE 10 je skoro všude asi o řád pomalejší, než Chrome a stará Opera.

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