Huvudinnehåll
Dataprogrammering
Sammanfattning: Objektorienterad design
Det här är en sammanfatting av vad vi gick genom om objektorienterad design.
När vi skapar program händer det ofta att vi vill skapa många olika objekt som delar liknande egenskaper - som en massa katter, som har lite olika pälsfärg och storlek, eller många knappar med olika texter och positioner. Vi vill kunna säga "såhär är en katt" och sedan säga "Vi skapar den här specifika katten och den här andra katten, och de kommer att ha vissa delade egenskaper och vissa saker som skiljer dem åt." Det är då vi vill använda objekt-orienterad design för att kunna definiera objekttyper och skapa flera olika instanser av dessa objekt.
För att definiera en objekttyp i JavaScript måste vi först definiera en "constructor"(konstruktors-funktion). Det är en funktion som vi sedan använder när vi vill skapa en ny instans av den sortens objekt. Här är en konstruktor-funktion för vår objekttyp
Book
(Bok):var Book = function(title, author, numPages) {
this.title = title;
this.author = author;
this.numPages = numPages;
this.currentPage = 0;
};
Funktionen tar in argument för de delar av objektet som kommer att skilja sig mellan de olika böckerna - titeln, författaren och antalet sidor. Sedan sätts objektets egenskaper till värdet på de argumenten, med hjälp av
this
nyckelordet. När vi använder this
i ett objekt så pekar vi till den aktuella instansen av det objekt vi jobbar med, vi pekar på det aktuella objektet självt. Vi måste lagra egenskaperna med this
för att objektet ska komma ihåg dem senare.För att skapa en instans av ett
Book
-objekt deklarerar vi en ny variabel att lagra den i, sedan använder vi new
-nyckelordet, följt av konstruktorns funktionsnamn och skickar de argument som konstruktorn vill ha:var book = new Book("Robot Dreams", "Isaac Asimov", 320);
Efter det kan vi komma åt de egenskaper som vi lagrade i objektet genom att använda punktnotation:
println("I loved reading " + book.title); // I loved reading Robot Dreams
println(book.author + " is my fav author"); // "Isaac Asimov" is my fav author
Vi tittar lite närmre på det här och kollar vad som skulle ha hänt om vi inte satt upp vår konstruktor-funktion korrekt:
var Book = function(title, author, numPages) {
};
var book = new Book("Little Brother", "Cory Doctorow", 380);
println("I loved reading " + book.title); // I loved reading undefined
println(book.author + " is my fav author"); // undefined is my favorite author
Om vi skickar argumenten till konstruktorn men inte använder
this
när vi lagrar dem, så kommer vi inte kunna komma åt dem senare! Objektet har glömt bort dem.När vi definierar objekttyper vill vi ofta knyta både egenskaper och beteende till dem - t.ex. ska alla våra kattobjekt kunna meow() och eat(). Så vi behöver kunna lägga till funktioner till våra objekttypsdefinitioner, och vi kan göra det genom att definiera funktionerna i det som kallas objektprototypen:
Book.prototype.readItAll = function() {
this.currentPage = this.numPages;
println("You read " + this.numPages + " pages!");
};
Det är som när vi definierar en funktion i vanliga fall, fast vi sätter den på
Book
s prototyp istället för att bara definiera funktionen globalt. Då vet JavaScript att den här funktionen kan anropas på alla bok
-objekt och att den här funktionen ska ha tillgång till this
på den book som funktionen anropas på.Då kan vi anropa funktionen (som vi nu kallar för metod, eftersom den är knuten till ett objekt), såhär:
var book = new Book("Animal Farm", "George Orwell", 112);
book.readItAll(); // You read 112 pages!
Kom ihåg att hela poängen med objektorienterad design är att det gör det enkelt för oss att skapa flera liknande objekt (objekt instanser). Vi tittar på hur det ser ut i kod:
var pirate = new Book("Pirate Cinema", "Cory Doctorow", 384);
var giver = new Book("The Giver", "Lois Lowry", 179);
var tuck = new Book("Tuck Everlasting", "Natalie Babbit", 144);
pirate.readItAll(); // You read 384 pages!
giver.readItAll(); // You read 179 pages!
tuck.readItAll(); // You read 144 pages!
Den koden ger oss tre böcker som liknar varandra - de har alla samma egenskaper och beteende, men är samtidigt olika. Vackert!
Nu, om vi föreställer oss hur världen ser ut, så är katter och hundar olika typer av objekt, så du skulle förmodligen skapa olika objekttyper för dem. Som en
Cat
och en Dog
objekttyp. En katt skulle kunna meow()
, en hund skulle kunna bark()
. Men de är också lika - både katten och hunden skulle eat
, de har båda en age
, en birth
och en death
. De är båda däggdjur, och det betyder att de delar många egenskaper, även om de samtidigt är olika.Det är då vi kan använda oss av objekt arv. En objekttyp kan ärva egenskaper och beteende från en förälder-objekttyp, men kan samtidigt ha egna unika egenskaper. Alla
Cat
s och Dog
s kan ärva från Mammal
(däggdjur), så att de inte skulle behöva uppfinna eat()
båda två. Hur skulle vi göra det i JavaScript?Vi går tillbaka till vårt bokexempel och säger att
Book
är av 'förälder'-objekttypen, och så skapar vi två objekttyper som ärver från den -Paperback
(pocketbok) och EBook
.En paperback är som en bok, men den skiljer sig åt på en punkt, åtminstone för vårt program: den har en omslagsbild. Så, vår konstruktor behöver ta fyra argument, för att ta in den extra informationen:
var PaperBack = function(title, author, numPages, cover) {
// ...
}
Nu vill vi inte göra allt arbete som vi redan gjort i
Book
-konstruktorn en gång till för att kunna spara de första tre argumenten - vi vill använda oss av det faktum att koden för det skulle vara densamma. Så vi kan faktiskt anropa konstruktorn Book
från PaperBack
-konstruktorn och skicka de argumenten:var PaperBack = function(title, author, numPages, cover) {
Book.call(this, title, author, numPages);
// ...
};
Vi behöver fortfarande lagra egenskapen
cover
(omslag) i det här objektet, så vi behöver en rad till för att göra det:var PaperBack = function(title, author, numPages, cover) {
Book.call(this, title, author, numPages);
this.cover = cover;
};
Nu har vi en konstruktor för vår
Paperback
, som har de egenskaper som Book
har, men vi vill också att Paperback
ska ärva Book's metoder. Det gör vi genom att berätta för programmet att PaperBack
-prototypen ska baseras på Book
-prototypen:PaperBack.prototype = Object.create(Book.prototype);
Vi vill antagligen också lägga till ett unikt beteende, som att kunna bränna den, och det kan vi göra genom att definiera funktioner på prototypen, efter kodraden ovan:
PaperBack.prototype.burn = function() {
println("Omg, you burnt all " + this.numPages + " pages");
this.numPages = 0;
};
Och nu ska vi skapa en paperback, läsa den och sen bränna den!
var calvin = new PaperBack("The Essential Calvin & Hobbes", "Bill Watterson", 256, "http://ecx.images-amazon.com/images/I/61M41hxr0zL.jpg");
calvin.readItAll(); // You read 256 pages!
calvin.burn(); // Omg, you burnt all 256 pages!
(Nåväl, vi kommer inte att bränna den, för det är en fantastisk bok, men kanske om vi fastnade i en glaciär-öken och desperat behövde värme för att inte dö.)
Och nu kan du se hur vi kan använda objektorienterade designprinciper i JavaScript för att skapa mer komplex data i våra program och modellera våra programvärldar bättre.
Vill du gå med i konversationen?
Inga inlägg än.