Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: Práce s objekty - Error x is not a function

Aktivity
Avatar
Patrik
Člen
Avatar
Patrik:22.10.2022 7:53

Ahoj,
v JavaScriptu jsem stále velice nezkušený a před moje prsty se dostal jeden error. Dá se říct, že si pouze hraju a snažím se pochopit funkcionalitu­.Pracuji s několika objekty a chci pomocí formuláře v html vytvořit mého Membera, který má základní atributy.

v app.js což je můj obsluhový soubor mám na tlačitku addEventListener

btn.addEventListener("click", mDB.createMemberForm);

Mám objekt, který je databáze pro Members MembersDatabase.js ,kde je metoda createMemberForm()

createMemberForm() {
        let name = memberform.name.value;
        let role = memberform.role.value;
        let status = memberform.status.value;

        console.log(`${name},${role},${status}`);
        this.createMember(name, role, status);
    }

V této metodě volám další metodu objektu MembersDatabase.js a zde příjde error. Metody samy o sobě fungují, ale s použitím tlačítka hází chybu. Když vyplním formulář a zmáčku tláčítko vyskočí na mě tato hláška

Uncaught TypeError: this.createMember is not a function
at HTMLButtonEle­ment.createMem­berForm

Metoda createMember())

createMember(name, role, status) {
       if (status === "member") {
           const member = new Member(name, role);
           this.memberDB.push(member);
       } else if (status === "familymember") {
           const familyMember = new FamilymMember(name, role);
           this.memberDB.push(familyMember);
       } else {
           console.log("Error  - neplatný status vytváření membera");
       }
   }

Zkusil jsem: Zkoušel jsem přesunout btn.addEventLis­tener() přímo do objektu MembersDatabase.js a nic to nevyřešilo. Říkal jsem si, jestli to není tím, že addEventListener si dokáže zavolat metodu createMemberForm(), ale poté se už nedokáže přesměrovat na jinou metodu objektu.

Chci docílit: Rád bych věděl, jak tenhle problém funguje. Vím, že se to bude dát nějak obejít, ale rád bych věděl jak přemýšlí počítač a proč to nejde tímto způsobem.

Budu rád za každé vaše rady, vysvětlení a nasměrování.

Editováno 22.10.2022 7:53
 
Odpovědět
22.10.2022 7:53
Avatar
Jurajs
Člen
Avatar
Odpovídá na Patrik
Jurajs:22.10.2022 9:47

Ahoj, nemá být nahodou v tom addEventListe­ner("click", createMemberForm);
Na místo toho to ? mDB.createMem­berForm) ?

Editováno 22.10.2022 9:49
 
Nahoru Odpovědět
22.10.2022 9:47
Avatar
Patrik
Člen
Avatar
Patrik:22.10.2022 11:32

Ahoj,díky za reakci. mDB je instance třídy MembersDatabase.js a celé to je v jiném javascript souboru(app.js). Možná to dělám zbytečně složitě 😀 Tak nějak poprvé se hrabu v objektech, takže je to pro mě trošku guláš.

 
Nahoru Odpovědět
22.10.2022 11:32
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:23.10.2022 20:16

Muzes z toho vseho vycucat kod a vyrobit jednoduchy priklad? Radi bycho si tu hlasku vygenerovali sami. Takhle je to spis tipovacka naslepo jen podle kodu, kde nemusi byt chyba.

 this.createMember is not a function // pise, ze to neni funkce. tak si to alertni a zjisti, co to je?
HTMLButtonElement.createMemberForm // tady pise, ze to vola z buttonu. Coz je nesmysl.
// btn.addEventListener("click", mDB.createMemberForm);
// timhle navazujes na buton nejakou externi funkci, ale, pokud mas tento radek spatne a mas tam this, pak ta hlaska dava smysl
// btn.addEventListener("click", this.createMemberForm); // this v tomto pripade odkazuje nejspis na button a ten funkci createMemberForm nema

A z toho erroru jsi vynechal cislo radku, ktery by mohl byt zasadni.

Editováno 23.10.2022 20:17
 
Nahoru Odpovědět
23.10.2022 20:16
Avatar
Patrik
Člen
Avatar
Avatar
Odpovídá na Patrik
Petr Štechmüller:24.10.2022 7:21

Ahoj, než se tu začnou rozvíjet nějaké bludné teorie, nejdříve napíšu řešení a pak vysvětlení.

ŘEŠENÍ

btn.addEventListener("click", mDB.createMemberForm.bind(mDB));
// nebo
btn.addEventListener("click", () => mDB.createMemberForm());

VYSVĚTLENÍ
"Problém je v tzv. scope. V JS to funguje maličko jinak než v ostatních OOP jazycích co se týče ukazatele this a tohle je jeden z těch podivných případů.
Ve tvé ukázce jsi předal funkci createMemberForm jako parametr addEventListener. Když pak nastane událost kliknutí na tlačítko, ukazatel this bude ukazovat na kontext toho kliknutí a ne na instanci tvojí MemberDatabase jak by se dalo očekávat.

Na zkoušku si můžeš vypsat do konzole, na co ukazatel this ukazuje ve tvém případě.
Měl bys vidět něco takového:

<button id="createMemberBtn">
.....

To znamená, že this je vlastně to tlačítko samotné a vůbec neukazuje na MemberDatabase.

První příklad v řešení je použití "magické" metody bind, která právě změní kontext, takže this už bude tvoje MemberDatabase.
Druhý příklad v řešení používá jednoduše anonymní funkci, ve které se teprve metoda createMemberForm zavole. Tím se opět změní kontext a this už bude ukazovat na správnou instanci.

Doufám, že je to pochopitelný :)

Nahoru Odpovědět
24.10.2022 7:21
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:24.10.2022 9:27
btn.addEventListener("click", mDB.createMemberForm); // 1
btn.addEventListener("click", mDB.createMemberForm.bind(mDB)); // 2

1 a 2 jsou zatracene rozdil.

//1
var xxx = function (event) {...}
btn.addEventListener("click", xxx);

// 1
function yyy (event) {...}
btn.addEventListener("click", yyy);

// 3
function zzz (cokoliv) {...}
btn.addEventListener("click", function (event) { zzz(neco); } ); // nebo...
btn.addEventListener("click", (event) => zzz(neco); );

// 2
alert(aaa.funkce.bind(bbb)) // vysledek bind operace returnuje true nebo false a boolean preci neni typu function
//console.log(aaa.funkce.bind(bbb))
btn.addEventListener("click", aaa.funkce.bind(bbb));
btn.addEventListener("click", true); // true neni event

O bind jinak nic nevim, tak s tim ti neporadim. Ja bych se tomu prikazu spis vyhl.

 
Nahoru Odpovědět
24.10.2022 9:27
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:24.10.2022 9:43

Aha, tak koukam, ze je problem jiny. Tu moji odpoved k BIND uplne ignoruj. Koukal jsem do dokumentace a bind skutecne vraci puvodni objekt https://developer.mozilla.org/…unction/bind
A nebo by asi fungovalo tez

//        this.createMember(name, role, status);
        mDB.createMember(name, role, status);

Kdyz totiz vola event, tak this pro ne plati na puvodni objekt, ve kterem event vytvaris. Coz je btn.
Na podobny problem narazis i pri praci setInterval.

Editováno 24.10.2022 9:45
 
Nahoru Odpovědět
24.10.2022 9:43
Avatar
Peter Mlich
Člen
Avatar
Odpovídá na Peter Mlich
Peter Mlich:24.10.2022 9:48

oprava: Kdyz totiz volas event, tak this je objekt, ve kterem event vytvaris. Coz je btn. Ikdyz to mas mysleno jinak a v jinych jazycich je to ok. Je to takova chybka js pro vsechny eventy.

 
Nahoru Odpovědět
24.10.2022 9:48
Avatar
Patrik
Člen
Avatar
Patrik:24.10.2022 10:31

Děkuji oboum za vysvětlení. Sice jsem si musel vysvětlení přečíst asi 3x, ale už jsem to pochopil 😀 Možná ještě navážu: je ještě nějaký příklad, kdy this vrací element v HTML?

 
Nahoru Odpovědět
24.10.2022 10:31
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:24.10.2022 12:41
btn.addEventListener("click", mDB.createMemberForm); // je skoro totez jako
bt.onclick = mDB.createMemberForm;
alert (bt.onclick); // alert ti pak zobrazi js kod funkce

// a kdybys to napsal primo, tak je ti to asi jasne
bt.onclick = function() {/*...*/    this.createMember(name, role, status); /*...*/   }

V tomto pripade je celkem jasne, ze this odkazuje na button. A to presne prohlizec udela, zkopiruje text kodu a znovu jej prelozi
Je to jakysi bug JS a nespis se to hned tak nezmeni, pac vsechny stranky s tim pocitaji.
Jestli jsou nejake dalsi priklady, tak se tykaji asynchronich udalosti, jako treba cteni souboru, dat, httprequest a jak jsem psal, casovacu setTimeout, setInterval. Proste, spesl udalost/event, ktery bezi nezavisle na ostatnim kodu, v jinem vlakne, jakoby.

 
Nahoru Odpovědět
24.10.2022 12:41
Avatar
JsonKody
Člen
Avatar
JsonKody:4.11.2022 10:55

Wtf? xDDDD

Petr Štechmüller tu naprosto spravne napise jak to s tim this je a ze nemuzes jen tak nekam narvat metodu protoze ztratis kontext toho ze je to medota -> je treba to nabindovat na puvodni objekt ..

.. a pak tady Peter Mlich napise roman o tom ze by to nepouzival a ze nevi co je bind.
KEKW

 
Nahoru Odpovědět
4.11.2022 10:55
Avatar
JsonKody
Člen
Avatar
Odpovídá na JsonKody
JsonKody:4.11.2022 11:07

no koukam, ze nakonec se to vyresilo spravne ..

Co ja vim tak this vraci ten dotycny HTML element jenom pri eventListenerech, protoze je to sikovne, ale clovek musi vedet jak funguje JS jinak padne do podobnych pasti.

Uz jen z toho ze je to nejaka funkce ktera prebira jen jinou funkci muzes (pokud vis jak funcuje JS) automaticky rict ze je spatny napad tam predavat metodu jen tak a ocekavat ze ona bude vedet z jakeho objektu pochazi - nebude.
JS je velmi tvarny a klidne si muzes pujcovat metody objektu a pouzivat je jako funkce nekde uplne jinde, volat je s jinym kontextem, na jinych objektech atd. ;)

 
Nahoru Odpovědět
4.11.2022 11:07
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 13 zpráv z 13.