Аб’ектна-арыентаванае праграмаваньне

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

var person1 = { title: "Dr.", lastName: "Seuss" };
var person2 = { title: "President", lastName: "Nixon" };
var person3 = { title: "Mr.", lastName: "Rogers" };

title і lastName завуцца уласьцівасьцямі, а інфармацыя якая захоўваецца ў іх завецца значэньнямі (values). Імя зменнай на самой справе не мае значэння – толькі для таго, каб зрабіць код чытаным.

Паколькі ўсе нашыя людзі маюць аднолькавыя ўласцівасці, мы можам стварыць функцыю, ў якую можа быць перададзены любы з іх:

var sayHello = function(person) {
    alert("Hello, " + person.title + " " + person.lastName + "!");
};

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

var people = [person1, person3, person3];
people.forEach(function(person) {
    sayHello(person);
});

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

var cow = { name: 'cow', sound: 'moo' };
var horse = { name: 'horse', sound: 'neigh' };
var fox = { name: 'fox', sound: 'Fraka-kaka-kaka-kaka-kow!' };

var farmAnimals = [cow, horse, fox];

var makeNoise = function(animal) {
    console.log('The ' + animal.name + ' says ' + animal.sound + '.');
};

farmAnimals.forEach(function(animal) {
    makeNoise(animal);
});

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

address-book.html
<!DOCTYPE html>
<html>
<head>
    <link href="css/bootstrap.css" rel="stylesheet" type="text/css">
    <link href="css/styles.css" rel="stylesheet" type="text/css">
    <script src="js/jquery-2.1.1.js"></script>
    <script src="js/scripts.js"></script>
    <title>Address book</title>
</head>
<body>
    <div class="container">
        <h1>Address book</h1>

        <div class="row">
            <div class="col-md-6">
                <h2>Add a contact:</h2>
                <form id="new-contact">
                    <div class="form-group">
                    <label for="new-first-name">First name</label>
                    <input type="text" class="form-control" id="new-first-name">
                    </div>
                    <div class="form-group">
                    <label for="new-last-name">Last name</label>
                    <input type="text" class="form-control" id="new-last-name">
                    </div>
                    <div class="form-group">
                    <label for="new-address">Address</label>
                    <input type="text" class="form-control" id="new-address">
                    </div>

                    <button type="submit" class="btn">Add</button>
                </form>

                <h2>Contacts:</h2>
                <ul id="contacts">

                </ul>
            </div>
        </div>
    </div>
</body>
</html>
scripts.js
$(document).ready(function() {
    $("form#new-contact").submit(function(event) {
        event.preventDefault();

        var inputtedFirstName = $("input#new-first-name").val();
        var inputtedLastName = $("input#new-last-name").val();
        var inputtedAddress = $("input#new-address").val();
        var newContact = { firstName: inputtedFirstName, lastName: inputtedLastName, address: inputtedAddress };

        $("ul#contacts").append("<li><span class='contact'>" + newContact.firstName + " " + newContact.lastName + "</span></li>");

        $("input#new-first-name").val("");
        $("input#new-last-name").val("");
        $("input#new-address").val("");
    });
});

Цяпер, калі мы запусцім нашу вэб-старонку, кожны раз, калі мы дадаем кантакт, ён дадаецца ў спіс кантактаў.

Гэта ня вельмі цікава. Мы маглі б зрабіць гэта ўсё з jQuery без выкарыстаньня аб’ектаў. Давайце зробім нашу старонку складаней, каб паказаць моц аб’ектаў. Мы дадамо такі функцыянал, каб пры націсканьні на кантакт, карыстальнік змог убачыць поўную інфармацыю аб кантакце.

Па-першае, абнавіце наш HTML і дадайце наступны код у канцы <div class="row">:

address-book.html
<div class="col-md-6">
    <div id="show-contact">
        <h2></h2>

        <p>First name: <span class="first-name"></span></p>
        <p>Last name: <span class="last-name"></span></p>
        <p>Address: <span class="address"></span></p>
    </div>
</div>

Элемент “show-contact” будзе схаваны спачатку. Мы таксама дададзім клас, каб некаторыя элементы выглядалі клікабельна:

styles.css
#show-contact {
    display: none;
}

.contact {
    cursor: pointer;
    color: #0088cc;
}

.contact:hover {
    text-decoration: underline;
}

Цяпер, давайце абновім JavaScript: дададзім да канца функцыі апрацоўкі формы наступны код:

scripts.js
$(".contact").last().click(function() {
    $("#show-contact").show();
    $("#show-contact h2").text(newContact.firstName + " " + newContact.lastName);
    $(".first-name").text(newContact.firstName);
    $(".last-name").text(newContact.lastName);
    $(".address").text(newContact.address);
});

Ці можаце Вы сабе ўявіць, як бы складана было пабудаваць гэтую старонку, выкарыстоўваючы толькі jQuery? Спадзяюся, Вы пачынаеце бачыць моц аб’ектна-арыентаванага праектавання.

Адносіны паміж аб’ектамі

Давайце даведаемся, як пабудаваць больш складаныя праграмы, якія выкарыстоўваюць некалькі аб’ектаў.

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

var pdx = { name: "Portland" };
var sfo = { name: "San Francisco" };
var sea = { name: "Seattle" };
var cso = { name: "Aktau" };
var dzn = { name: "Zhezkazgan" };

var usa = { name: "United States of America" };
var kazakhstan = { name: "Kazakhstan" };
var uruguay = { name: "Uruguay" };

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

var pdx = { name: "Portland" };
var sfo = { name: "San Francisco" };
var sea = { name: "Seattle" };
var cso = { name: "Aktau" };
var dzn = { name: "Zhezkazgan" };

var usa = { name: "United States of America", cities: [pdx, sfo, sea] };
var kazakhstan = { name: "Kazakhstan", cities: [cso, dzn] };
var uruguay = { name: "Uruguay", cities: [] };

Уласьцівасьц, якая зьяўляецца масівам з іншымі аб’ектамі – вельмі частая практыка ў аб’ектна-арыентаваным праграмаваньні. Цяпер мы можам даведацца пра спіс гарадоў, якія ёсьць у краіне:

usa.cities.forEach(function(city) {
    console.log("Let's go to " + city.name + "!");
});

Мы таксама можам дадаць горада да краіны пасля таго як аб’ект ужо створаны:

var mlz = { name: "Melo" };
uruguay.cities.push(mlz);

uruguay.cities вертае масіў, а потым push() дадае новы аб’ект туды.

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

var tomatoes = { name: "Tomatoes", price: 2.99 };
var cucumbers = { name: "Cucumbers", price: 0.99 };
var onions = { name: "Onions", price: 0.79 };

var groceryStore = { name: "Michael's corner market", products: [tomatoes, cucumbers, onions] };

var iPhone = { name: "iPhone", price: 699 };
var android = { name: "Android", price: 499 };
var windowsPhone = { name: "Windows Phone", price: 399 };

var phoneStore = { name: "RadioShack", products: [iPhone, android, windowsPhone] };

var stores = [groceryStore, phoneStore];

stores.forEach(function(store) {
    console.log(store.name + " sells:");
    store.products.forEach(function(product) {
        console.log(product.name);
    });
    console.log("\n");
});

Адрасная кніга з адносінамі

Цяпер, давайце дададзім тое, пра што мы даведаліся ў старонку адраснай кнігі. Пачнем са зьмяненьня HTML і дадазім у форму больш палей для адраса:

address-book.html
<!DOCTYPE html>
<html>
<head>
    <link href="css/bootstrap.css" rel="stylesheet" type="text/css">
    <link href="css/styles.css" rel="stylesheet" type="text/css">
    <script src="js/jquery-1.11.0.js"></script>
    <script src="js/scripts.js"></script>
    <title>Address book</title>
</head>
<body>
    <div class="container">
        <h1>Address book</h1>

        <div class="row">
            <div class="col-md-6">
                <h2>Add a contact:</h2>
                <form id="new-contact">
                    <div class="form-group">
                        <label for="new-first-name">First name</label>
                        <input type="text" class="form-control" id="new-first-name">
                    </div>
                    <div class="form-group">
                        <label for="new-last-name">Last name</label>
                        <input type="text" class="form-control" id="new-last-name">
                    </div>

                    <div id="new-addresses">
                        <div class="new-address">
                            <div class="form-group">
                                <label for="new-street">Street</label>
                                <input type="text" class="form-control new-street">
                            </div>
                            <div class="form-group">
                                <label for="new-city">City</label>
                                <input type="text" class="form-control new-city">
                            </div>
                            <div class="form-group">
                                <label for="new-state">State</label>
                                <input type="text" class="form-control new-state">
                            </div>
                        </div>
                    </div>

                    <span class="btn btn-primary" id="add-address">Another address</span>

                    <button type="submit" class="btn">Add</button>
                </form>

                <h2>Contacts:</h2>
                <ul id="contacts">

                </ul>
            </div>

            <div class="col-md-6">
                <div id="show-contact">
                    <h2></h2>

                    <p>First name: <span class="first-name"></span></p>
                    <p>Last name: <span class="last-name"></span></p>
                    <p>Addresses:</p>
                    <ul id="addresses">

                    </ul>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

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

scripts.js
$(document).ready(function() {
    $("#add-address").click(function() {
        $("#new-addresses").append('<div class="new-address">' +
                '<div class="form-group">' +
                    '<label for="new-street">Street</label>' +
                    '<input type="text" class="form-control new-street">' +
                '</div>' +
                '<div class="form-group">' +
                    '<label for="new-city">City</label>' +
                    '<input type="text" class="form-control new-city">' +
                '</div>' +
                '<div class="form-group">' +
                    '<label for="new-state">State</label>' +
                    '<input type="text" class="form-control new-state">' +
                '</div>' +
            '</div>');
    });
    ...

Для таго, каб наш код, які ўстаўляе некалькі радкоў HTML у DOM выглядаў чытабельна, мы разбілі яго на некалькі радкоў па розным лініям, выкарыстоўваючы + для аб’яднання іх. Водступы тыя ж што і ў HTML.

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

scripts.js
...
$("form#new-contact").submit(function(event) {
    event.preventDefault();

    var inputtedFirstName = $("input#new-first-name").val();
    var inputtedLastName = $("input#new-last-name").val();

    var newContact = { firstName: inputtedFirstName, lastName: inputtedLastName, addresses: [] };

    $(".new-address").each(function() {
        var inputtedStreet = $(this).find("input.new-street").val();
        var inputtedCity = $(this).find("input.new-city").val();
        var inputtedState = $(this).find("input.new-state").val();

        var newAddress = { street: inputtedStreet, city: inputtedCity, state: inputtedState };
        newContact.addresses.push(newAddress);
    });


    $("ul#contacts").append("<li><span class='contact'>" + newContact.firstName + "</span></li>");

    $(".contact").last().click(function() {
        $("#show-contact").show();

        $("#show-contact h2").text(newContact.firstName);
        $(".first-name").text(newContact.firstName);
        $(".last-name").text(newContact.lastName);

        $("ul#addresses").text("");
        newContact.addresses.forEach(function(address) {
            $("ul#addresses").append("<li>" + address.street + ", " + address.city + ", " + address.state + "</li>");
        });
    });

    $("input#new-first-name").val("");
    $("input#new-last-name").val("");
    $("input#new-street").val("");
    $("input#new-city").val("");
    $("input#new-state").val("");
    });
});

Тут, у нас ёсць новы цыкл: калі мы хочам перабраць ўсе элементы ў выбарцы jQuery, мы выкарыстоўваем метад .each () . Ён вельмі падобны на forEach () для масіваў, але замест таго, каб перадаваць кожны элемент у параметр, мэтад выкарыстоўвае this , каб звярнуцца да бягучага элементу.

Мы таксама выкарыстоўваем метад find () , які праглядае ўсе дзіцячыя элементы абранага элемента і адбірае тыя, якія адпавядаюць крытэрам, перададзеныя ў якасці аргументу. Метад children() робіць тое ж самае, але children() праходзіць толькі адзін узровень ўніз, у той час як find() будзе шукаць у дзяцей, іх дзецяей і гэтак далей. Так як нашы інпуты ўнутры form-group <div> мы павінны прайсці ўніз на два ўзроўні.

Уф! Гэта было шмат!

Адрасная кніга, працяг

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

Спіс To-do

Continue your to do list, so that you can have multiple lists, each with its own set of tasks. Here's a wireframe of how it should roughly look:

Працягніце рабіць спіс to-do – дадайце магчымасьць мець некалькі спісаў, кожны са сваім наборам задач. Вось як гэта павінна прыкладна выглядаць:

mockup of to do list

Гэта wireframe – распаўсюджаны інструмент для адлюстраваньня сутнасци, як старонка павінна выглядаць, без паглыбленьня ў дробязі пра кожны піксель.

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