Мэтады

Цяпер, калі ў Вас быў шанец папрактыкавацца ў выкарыстанні аб’ектаў для захоўвання інфармацыі, давайце звернемся да другой асноўнай функцыі аб’ектаў: даданне паводзін. Аб’екты, як часта кажуць, ўвасабляюць стан і паводзіны ; ўласцівасці захоўваюць іх стан, а мэтады дадаюць ім паводзіны.

Што мы маем на ўвазе паводзіны? Ну, напрыклад, масіў на самай справе гэта аб’ект. Ён мае такія паводзіны як “цыкл” – мэтад (forEach()), даданне і выдаленне элементаў (push() і pop()). Масіў мае адну ўласцівасць:length

JavaScript таксама “заварачвае” прымітыўныя тыпы (як радкі і лікі) у аб’екты. Лікі маюць такія паводзіны як пераўтварэнне паміж сістэмамі з фіксаванай кропкай і экспанентнай натацыяй (toFixed () і toExponential ()). Радкі маюць такія паводзіны як вяртанне сымбала па індэксу (charAt()) і вызначэнне таго, ці ўтрымоўвае радок іншы радок (contains() ).

Зараз давайце зробім нашыя ўласныя метады на аб’ектаў. Напрыклад, мы маглі б мець аб’ект, які ўяўляе сабой чалавека, і стварыць метад для таго, каб сказаць прывітанне:

var suzy = {
    name: "Suzy McSuzerson",
    sayHello: function() {
        alert("Hello there!");
    }
};

suzy.sayHello();

Акрамя таго, мы маглі б стварыць іншы мэтад для таго, каб развітацца:

suzy.sayGoodbye = function() {
    alert("Goodbye now!");
};

suzy.sayGoodbye();

Мэтад – зьяўляецца проста ўласцівасьцю, значэньне якой складае функцыя. Для выкліку метаду, мы выкарыстоўваем тыя ж абазначэнні, што і для ўласцівасцей, але дадаем () да канца, так што JavaScript выконвае метад, а не проста вяртае, саму функцыю.

Цяпер, давайце трошкі зменім наш метад:

var suzy = {
    name: "Suzy McSuzerson",
    sayHello: function() {
        alert("Hello there! I'm Suzy McSuzerson.");
    }
};

Праблема тут у тым, што Сюзі можа аднойчы зьмяніць яе імя:

suzy.name = "Suzy McSousaphone";
suzy.sayHello();

Мы павінны адлюстроўваць яе імя ў залежнасці ад значэньня, якое мае ўласцівасьць name:

var suzy = {
    name: "Suzy McSuzerson",
    sayHello: function() {
        alert("Hello there! I'm " + this.name + ".");
    }
};

this – гэта ключавое слова, якое змяшчае спасылку на аб’ект, у якім выклікаецца функцыя. Кожны раз, калі Вы хочаце спаслацца на ўласцівасці аб’екта ўнутры аднаго з яго метадаў карыстаецеся this.

Зараз, калі мы зменім імя Сьюзэн, наш метад будзе заставацца ў курсе:

suzy.name = "Suzy McSousaphone";
suzy.sayHello();

Давайце праверым яшчэ адзін прыклад зараз:

var rectangle = {
    length: 22,
    width: 10,
    area: function() {
        return this.length * this.width;
    }
};

rectangle.area();

Даволі проста: мы ствараем аб’ект для прастакутніка, з парай уласцівасцяў для даўжыні і шырыні, і таксама метад, які вылічае плошчу прастакутніка

.

Цяпер, давайце ўключым пару метадаў у нашую адрасную кнігу:

scripts.js
...
var newContact = {
    firstName: inputtedFirstName,
    lastName: inputtedLastName,
    addresses: [],
    fullName: function() {
        return this.firstName + " " + this.lastName;
    }
};
...
var newAddress = {
    street: inputtedStreet,
    city: inputtedCity,
    state: inputtedState,
    fullAddress: function() {
        return this.street + " " this.city + " " + this.state;
    }
};
...
$("ul#contacts").append("<li><span class='contact'>" + newContact.fullName() + "</span></li>");
...
$("#show-contact h2").text(newContact.fullName());
...
$("ul#addresses").append("<li>" + address.fullAddress() + "</li>");
...

Класіфікатар трохкутнікаў

Давайце зараз зробім вось такую старонку, каб класіфікоўваць трыкутнікі:

wireframe of a triangle tracker webpage

Калі карыстальнік уводзіць няправільны трохкутнік, адлюстроўваецца алерт і трохкутнік не класіфікуецца.

Вы можаце выкарыстоўваць Ваш код з папярэдніх заняткаў для таго каб пабудаваць мэтад класіфікацыі трохкутніка. Стварыце мэтад type() у кожнага трохкутніка, які вяртае тып трыкутніка. Падказка: метад не павінен прымаць якія-небудзь аргументы, бо трыкутнік можа спасылацца на свае бакі з дапамогай ключавога слова this.

Пакуль не хвалюйцеся аб напісанні тэстаў; мы вернемся да гэтага ў наступным ўроку.

Калькулятар кошта дастаўкі

Зрабіць вэб-старонку, якая вылічае кошт перавозкі пакета. Для прыклада можна паглядзець на калькулятар Fedex. Зноў жа, выкарыстоўвайце аб’екты каб увасобіць логіку.

Прататыпы

Давайце яшчэ раз паглядзім на наш код для стварэння чалавека з мінулага ўрока:

var suzy = {
    name: "Suzy McSuzerson",
    sayHello: function() {
        alert("Hello there! I'm " + this.name + ".");
    }
};

А што калі нам трэба стварыць некалькі чалавек з мэтадам sayHello()? Мы павінны былі б зрабіць нешта накшталт гэтага:

var suzy = {
    name: "Suzy McSuzerson",
    sayHello: function() {
        alert("Hello there! I'm " + this.name + ".");
    }
};

var larry = {
    name: "Larry McLarryson",
    sayHello: function() {
        alert("Hello there! I'm " + this.name + ".");
    }
};

var lilly = {
    name: "Lilly McLillyson",
    sayHello: function() {
        alert("Hello there! I'm " + this.name + ".");
    }
};

Гэта жудасна шмат паўтораў мэтада sayHello(). У вэб-старонках, які мы рабілі да гэтага часу, мы павінны былі вызначыць метад толькі адзін раз, але зараз нашыя праграмы робяцца больш складанымі – некаторыя метады трэба выкарыстоўваць некалькі разоў. Было б лепш, калі б мы мелі асаблівы тып “чалавек”, які аўтаматычна меў бы метад sayHello ().

У JavaScript, мы робім гэта шляхам стварэння прататыпа . Прататып – гэта аб’ект, копіі якога, вы выкарыстоўвайце ў якасці асновы для іншых аб’ектаў. Мы можам вызначыць sayHello () у прататыпе, а потым, калі нам трэба стварыць новага чалавека, мы можам выкарыстоўваць гэты прататып у якасці адпраўной кропкі. Вось як гэта выглядае:

var Person = {
    sayHello: function() {
        alert("Hello there! I'm " + this.name + ".");
    }
};

var suzy = Object.create(Person);
suzy.name = "Suzy McSuzerson";
suzy.sayHello();

var larry = Object.create(Person);
larry.name = "Larry McLarryson";
larry.sayHello();

var lilly = Object.create(Person);
lilly.name = "Lilly McLillyson";
lilly.sayHello();

Традыцыйна, JavaScript распрацоўшчыкі імкнуцца выкарыстоўваць загалоўную літару, каб пачаць імя зменнай у якой знаходзіцца прататып. Але насамрэч, любы аб’ект у JavaScript можа быць выкарыстаны ў якасці прататыпа для стварэння іншага аб’екта.

Калі вы хочаце выкарыстоўваць аб’ект у якасці прататыпа для іншага аб’екта, Вы проста перадаёце гэты аб’ект у Object.create (). Вяртаецца новы аб’ект, які мае ўсе тыя ж ўласцівасці і метады, як і ў зыходнага аб’екта. Новы аб’ект часта называюць асобнік (экзэмпляр) прататыпа.

Давайце разглядзім іншы прыклад таго, як выкарыстоўваць прататыпнае ўспадкаваньне:

var BankAccount = {
    balance: 0,
    withdraw: function(amount) {
        this.balance = this.balance - amount;
    },
    deposit: function(amount) {
        this.balance = this.balance + amount;
    }
};

var myBankAccount = Object.create(BankAccount);
myBankAccount.balance;
myBankAccount.deposit(20);
myBankAccount.balance;

var yourBankAccount = Object.create(BankAccount);
yourBankAccount.balance;
yourBankAccount.withdraw(1000000);
yourBankAccount.balance;

Тут мы вызначаем прататып BankAccount, які мы можам выкарыстоўваць для стварэння новых асобнікаў банкаўскіх рахункаў, так што яны ствараюцца з убудаванымі метадамі withdraw() і deposit(), а таксама балансам роўным 0.

Выкарыстанне прататыпаў дазваляе таксама пісаць спецыфікацыі для нашых метадаў:

specs.js
describe("BankAccount", function() {
    describe("deposit", function() {
        it("adds the amount to the balance", function() {
            var testBankAccount = Object.create(BankAccount);
            testBankAccount.deposit(10);
            testBankAccount.balance.should.equal(10);
        });
    });
    
    describe("withdraw", function() {
        it("subtracts the amount from the balance", function() {
            var testBankAccount = Object.create(BankAccount);
            testBankAccount.withdraw(10);
            testBankAccount.balance.should.equal(-10);
        });
    });
});

Як правіла, маецца знешні мэтад describe для кожнага прататыпа (напрыклад, BankAccount), а ўсе спецыфікацыі для кожнага метаду апісваюцца ва ўнутраным describe з імем гэтага метаду (напрыклад deposit).

З гэтага моманту, Вы павінны выкарыстоўваць прататыпныя вызначэнні метадаў (і таксама вызначаць любыя пачатковыя значэння уласцівасцяў). Выкарыстоўвайце BDD, каб дапамагчы Вам напісаць гэтыя метады.

Падлік выдаткаў

Ваша мэта ў гэтым практыкаванні навучыцца выкарыстоўваць прататыпнае ўспадкоўваньне.

Зрабіце вэб-старонку якая б дапамагала б Вам адсочваць выдаткі. Для пачатку проста зрабіце форму, дзе карыстальнікі могуць ўводзіць апісанне і колькасць для кожнай пакупкі, і спіс усіх купляў.

Макет якасці расходу

Дадайце ўласьцівасьць quantity і мэтад totalCost() . Зрабіце прататып пад назвай Purchase, каб ствараць аб’екты для пакупак. Заўсёды добрая ідэя выбраць такое імя для прататыпа, якое дакладна адпавядае рэальнай практычнай мэце выкарыстаньня.

Пераканайцеся што Вы рэалізавалі ўсе патрабаваньні. Калі Вы ўсе зробіце і Вам будзе сумна дадайце яшчэ наступны функцыянал.

Улік выдаткаў ня вельмі карысны, калі Вы ня можаце катагарызоўваць Вашыя выдаткі. Зрабіце форму, дзе карыстальнікі могуць ствараць новыя катэгорыі. Калі карыстальнікі выбірае катэгорыю, пералічваюцца ўсе пакупкі ў катэгорыі і зьяўляецца форма, каб дадаць пакупку ў гэтую катэгорыю:

Макет якасці расход з катэгорыямі

Вы павінны зрабіць прататып пад назвай Category для гэтай функцыі. Дадайце метад у прататып Category, які дазваляе карыстальнікам разлічыць агульную суму, якую яны патрацілі ў гэтай катэгорыі.

Мэтад ініцыялізацыі (initialize)

Вы магчыма пачынаеце стамляцца ад усіх крокаў, якія мы павінны рабіць кожны раз, калі ствараецца асобнік: стварыць аб’ект, стварыць розныя ўласцівасці, ствараць пустыя масівы, дадаць у іх аб’екты, і гэтак далей. Давайце створым метад, каб зрабіць гэта прасцей.

Мы пачнем з чаго-небудзь простага: я хацеў мець магчымасьць стварыць кантакт і распавесьці яму сваё імя і прозвішча – усё на адным дыханні. Мы пачнем са спецыфікацыі, каб апісаць гэтыя паводзіны:

specs.js
describe("Contact", function() {
    describe("initialize", function() {
        it("sets the first and last name", function() {
            var testContact = Object.create(Contact);
            testContact.initialize("Mary", "Jane");
            testContact.firstName.should.equal("Mary");
            testContact.lastName.should.equal("Jane");
        });
    });
});

Цяпер давайце напішам метад:

scripts.js
var Contact = {
    initialize: function(initializedFirstName, initializedLastName) {
        this.firstName = initializedFirstName;
        this.lastName = initializedLastName;
    }
};

Звярніце ўвагу, тут мы маем параметр initializedFirstName, які прымае першы аргумент initialize(); і ў нас таксама ёсць уласцівасьць з імем firstName, які ўсталёваўецца роўным гэтаму параметру. Дапокуль існуе аб’ект, значэнне ўласцівасці захоўваецца. Зменныя (уключаючы параметры) – гэта часовыя дадзеныя ў функцыі; як толькі функцыя скончвае выкананьне, інфармацыя знікае.

Цяпер мы можам раскласці гэты код:

scripts.js
var newContact = Object.create(Contact);
newContact.firstName = inputtedFirstName;
newContact.lastName = inputtedLastName;
newContact.addresses = [];

у гэты:

scripts.js
var newContact = Object.create(Contact);
newContact.initialize(inputtedFirstName, inputtedLastName);
newContact.addresses = [];

Метад initialize() добры пачатак, і я хачу, каб выкарыстоўваць яго далей. Давайце гэта наладзіць уласцівасьць addresses так, як на зручна. Па-першае, спецыфікацыя:

specs.js
describe("Contact", function() {
    describe("initialize", function() {
        it("sets up an empty array for the addresses property", function() {
            var testContact = Object.create(Contact);
            testContact.initialize("Mary", "Jane");
            testContact.addresses.should.eql([]);
        });
    });
});

І потым код:

scripts.js
var Contact = {
    initialize: function(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.addresses = [];
    }
}

У цяперашні час наш інтэрфейс павінен працаваць:

scripts.js
var newContact = Object.create(Contact);
newContact.initialize(inputtedFirstName, inputtedLastName);

Тамагочы

Гадоў 15 таму гульня Тамагочы была вельмі папулярна на працягу некаторага часу. Тамагочы былі накшталт электронных хатніх жывёл, якія Вы насілі з сабой і ціскаючы па кнопкам кармілі тамагочы, гулялі з ім, ставілі яго ў рэжым сну. Калі яму не даваць дастатковую колькасць ежы і ўвагі, ён памрэ.

Давайце зробім вэб-старонку Tomagotchi. На старонцы павінна быць кнопка, каб праверыць тамагочы і паглядзець, як ён маецца. Іншыя кнопкі выкарыстоўваюцца для таго, каб накарміць яго, гуляць з ім, усталёўваць у рэжым сну. Калі Вы не націскаеце гэтыя кнопкі досыць часта, пры праверцы ён павінен быць мёртвы.

Вось прыклад спецыфікацыі якую можна выкарыстоўвацю пры будаўніцтве свайго Tomagotchi:

specs.js
describe("Tamagotchi", function() {
    describe("initialize", function() {
        it("sets the name and a few other properties", function() {
            var myPet = Object.create(Tamagotchi);
            myPet.initialize("lil dragon");
            myPet.name.should.equal("lil dragon");
            myPet.foodLevel.should.equal(10);
            myPet.sleepLevel.should.equal(10);
            myPet.activityLevel.should.equal(10);
        });
    });
    
    describe("timePasses", function() {
        it("decreases the amount of food the Tamogatchi has left by 1", function() {
            var myPet = Object.create(Tamagotchi);
            myPet.initialize("lil dragon");
            myPet.timePasses();
            myPet.foodLevel.should.equal(9);
        });
    });
    
    describe("isAlive", function() {
        it("is alive if the food level is above 0", function() {
            var myPet = Object.create(Tamagotchi);
            myPet.isAlive().should.equal(true);
        });
    
        it("is dead if the food level is 0", function() {
            var myPet = Object.create(Tamagotchi);
            myPet.foodLevel = 0;
            myPet.isAlive().should.equal(false);
        });
    });
});

Гэта вельмі грубае набліжэнне гульні, бо час праходзіць толькі тады, калі мы кажам яму прайсьці (кожны раз, калі мы правяраем тамагочы, мы можам запускаць метад timePasses()).

Шыбеніца

Зрабіць праграму, каб гуляць у шыбеніцу.

Калі вы не знаёмыя з шыбеніцай, яна працуе нешта накшталт гэтага:

    ________________
   /\               |
   \/               |
    |               |
 -------            |
    |               |
    |               |
   /\               |
  /  \              |
              ______|_____


__ __ __ __ __ __

Прабелы ў ніжняй частцы прадстаўляць літары слова – у дадзеным выпадку, слова даўжынёй шэсць літар. На кожным кроке, гулец павінен адгадаць літару. Калі слова мае сымбал, ён дадаецца замест пустога месца:

    ________________
    |               |
                    |
                    |
                    |
                    |
                    |
                    |
                    |
              ______|_____


b __ b b __ __

Калі сымбал не ў слове, да чалавека на шыбеніцы дадаецца частка слова

    ________________
   /\               |
   \/               |
                    |
                    |
                    |
                    |
                    |
                    |
              ______|_____


b __ b b __ __

a

Калі гулец адгадвае ўсе літары ў слове, ён выігрывае. Калі цела чалавека завершаны і слова не адгадана – гулец губляе.

Пабудуйце прыкладанне для гульні ў шыбеніцу. Кампутар можа генераваць словы з папярэдне зададзенага спісу.

Падумайце аб тым, якія аб’екты Вы будзеце выкарыстоўваць, перад тым, як пачынаць.

Крыжыкі-Нулікі

Давайце зробім старонку крыху больш складаную, чым усё з чым мы працавалі на да гэтага часу: гульня Крыжыкі-Нулікі. Пачніце са стварэння такога варыянта гульні, дзе два чалавекі гуляюць адзін супраць аднаго; калі Вы вельмі хутка скончыце, зрабіце варыянт, дзе чалавек можа гуляць супраць кампутара.

Зрабіце чатыры прататыпа: Player, Space, Board і Game. Вось некалькі рэчаў (але не ўсё!) якія павінны рабіць асобнікі гэтых прататыпаў:

        
  • Гулец павінен ведаць, ці з’яўляецца ягоным знакам X або O .
  •     
  • Прастора павінна ведаць яе каардынаты і быць у стане быць пазначанай гульцом (напрыклад space.markBy(playerX)).
  •     
  • Дошка павінна стварыць 9 “прастораў” з адпаведнымі каардынатамі, і мець метад, вызначаючы, ці знаходзяцца побач тры “прасторы” адзначаныя тым жа гульцом. Дошка павінна мець магчымасць вярнуць прастору па каардынатам (напрыклад board.find (1, 2)).
  •     
  • Гульня павінна стварыць 2 гульцоў і дошку, умець пераходзіць да наступнага кроку, ведаць, які гулец робіць яго і мець магчымасьць сказаць ці скончана гульня.

Памятаеце і выкарыстоўвайце працэс BDD: чырвоны, зялёны, рэфактарынг! Вось некалькі спецыфікацыі, каб Вам было прасьцей пачаць:

specs.js
describe("Player", function() {
        describe("initialize", function() {
            it("is initialized with a symbol", function() {
                var testPlayer = Object.create(Player);
                testPlayer.initialize("X");
                testPlayer.symbol.should.equal("X");
            });
        });
    });

    describe("Space", function() {
        describe("initialize", function() {
            it("is initialized with an x and y coordinate", function() {
                var testSpace = Object.create(Space);
                testSpace.initialize(1, 2);
                testSpace.xCoordinate.should.equal(1);
                testSpace.yCoordinate.should.equal(2);
            });
        });

        describe("create"); // you write the rest of this one!

        describe("markBy", function() {
            it("lets a player mark the space", function() {
                var testPlayer = Object.create(Player);
                testPlayer.initialize("X");
                var testSpace = Object.create(Space);
                testSpace.initialize(1, 2);
                testSpace.markBy(testPlayer);
                testSpace.markedBy.should.equal(testPlayer);
            });
        });
    });

    describe("Board", function() {
        it("creates 9 spaces when it is initialized"); // you write the rest!
    });

Гульня Жыцьцё

Калі Вы ўжо зрабілі ўсё астатняе, вось Вам супер-заданьне. Напішыце гульню жыцьцё. Апісаньне вось тут: Гульня Жыцьцё.

Папярэдні занятак Наступны занятак