Prototip OOP
În programarea orientată pe clasă, mai întâi creați o clasă ca șablon și apoi creați un obiect bazat pe acesta. Pentru a construi mai multe tipuri de obiecte specifice, creăm un descendent al clasei. Asta este, vom face unele modificări în șablon și vom folosi noul șablon rezultat pentru a construi obiecte mai specifice.
În lumea reală, dacă trebuie să creați un scaun, ar trebui mai întâi să creați un proiect pe hârtie și să faceți apoi scaune pe baza acestui proiect. Proiectul aici este o clasă, iar scaunele sunt obiecte. Dacă doriți să faceți un balansoar, ați fi luat proiectul, ați făcut unele modificări și ați creat un scaun balansoar.
Object.create (null) creează un nou obiect gol. Apoi, vom adăuga proprietăți și funcții noului nostru obiect:
genericAnimal - un obiect și, în consecință, poate fi folosit:
Tocmai am creat o pisică, ca o clonă a unui animal normal. Putem adăuga proprietăți și funcții:
De asemenea, putem folosi pisica noastra ca prototip si sa cream mai multe pisici:
Cuvântul cheie nou și funcția constructorului
Deoarece aceasta nu este o clasă, este important să înțelegeți ce face apelul constructorului. Mai întâi, se creează un obiect gol, prototipul acestui obiect este setat la proprietatea prototip a constructorului, iar apoi funcția constructorului este apelată cu acest pointer la obiectul nou creat și obiectul este returnat la sfârșit.
Înțelegerea delegării și a prototipurilor de implementare
Prototipul OOP diferă de OOP tradițional prin faptul că nu există clase în el - numai obiecte care sunt moștenite de la alte obiecte.
Câteva exemple din codul anterior pot ilustra acest punct:
Următoarea linie creează un nou obiect gol cu un __proto__ nul:
Următoarea linie va crea un obiect gol cu __proto__. indicând spre rozătoare:
După cum puteți vedea, fiecare obiect conține o legătură cu prototipul său. Luați în considerare funcția Object.create. Se pare că funcția "clonează" obiectul părinte și proprietățile părinte sunt copiate la elementul copil, dar nu este. Atunci când capybara este creat de la rozătoare. capybara este un obiect gol, cu o legătură cu rozătoarele.
Dar atunci, dacă numim capybara.size imediat după creare, obținem dimensiunea S setată în obiectul părinte. Ce fel de magie e asta? La urma urmei, capybara nu are încă o proprietate de dimensiune. Cu toate acestea, atunci când scriem capybara.size. putem obține cumva mărimea proprietății prototipului.
Setarea proprietății este ușor diferită. Când instalăm capybara.size = 'XXL'. mărimea proprietăților noi. este creat în obiectul capybara. Și data viitoare vom încerca să accesăm capybara.size. o vom găsi direct în obiect cu valoarea 'XXL'.
Deoarece proprietatea prototipului este o referință, modificarea proprietăților obiectului prototip va afecta toate obiectele care utilizează prototipul. De exemplu, dacă după crearea unui rozătoare și a capybara rescriem funcția de descriere sau adăugăm o nouă funcție la genericAnimal. acestea vor deveni imediat disponibile pentru utilizare la rozătoare și capybara prin delegare.
Crearea unui Object.create
Object.create în acțiune
Desigur, dacă doriți, puteți scrie un constructor nou, setați-l ca un prototip pentru clona Math. Extindeți funcțiile prototip care vă plac și creați apoi obiectul în sine. Dar de ce treceți prin toate acestea pentru a face să pară o clasă atunci când prototipurile sunt atât de simple?
Acum putem suprascrie funcția aleatoare în obiectul myMath. Am scris o funcție care returnează numere aleatorii întregi în intervalul specificat de utilizator. În caz contrar, acesta numește părintele unei funcții aleatorii:
OOP bazat pe clase în comparație cu prototipul OOP
Ambele abordări au argumente pro și contra. Însă prototipul OOP este mai ușor de înțeles, este mai flexibil și mai dinamic.
Pentru a obține o idee despre natura sa dinamică, aruncăm o privire la următorul exemplu: ați scris un cod care folosește funcția indexOf în matrice. După ce l-ați scris și l-ați testat într-un browser bun, sunteți reticenți să îl verificați în Internet Explorer 8. După cum vă puteți aștepta, aveți probleme. Deoarece indexOf nu este definit în IE8.
Deci, ce faci? În POR pe bază de clasă, puteți rezolva această problemă prin definirea unei funcții într-o altă clasă "helper" care are ca parametru o array sau o listă și înlocuiește toate apelurile din codul dvs. Sau, puteți împărți Lista sau ArrayList în subclase, defini o funcție într-o subclasă și utilizați o nouă subclasă în loc de ArrayList.
Emoluția OOP bazată pe clase care pot merge prost
Luați în considerare următorul exemplu, scris cu pseudo-clase:
Acesta este un model de moștenire. Cu toate acestea, se întâmplă ceva amuzant aici - dacă verificați colonel.offspring și puff.offspring. apoi observați că fiecare dintre ele conține doi descendenți identici!
Deoarece seamănă cu un simplu OOP bazat pe o clasă, putem folosi această funcție pentru a construi o ierarhie de moștenire, așa cum se arată în următorul exemplu:
Toate acestea arată bine, atâta timp cât credeți că PPE de clasă. Dar dacă încercați table.events ['click.expand'] din consola, veți vedea "expand"! În orice caz, HideableTableView are un handler de expansiune a evenimentului. deși nu a fost definită în această clasă.
Puteți vedea această problemă în acțiune aici.
Problema de mai sus a apărut din același motiv ca cel descris în exemplul anterior. În Backbone.js trebuie să lucrați, încercând să faceți ca acesta să arate ca și ore, pentru a vedea un lanț de prototipuri ascunse în fundal. Odată ce ați înțeles modul în care lanțul prototip este structurat, puteți găsi o soluție simplă la această problemă.