Лекция 8. Функциональное и объектное программирование в Javascript.pdf

Full Transcript

Лекция 10. Функциональное и объектное программирование в JavaScript При первоначальном знакомстве с лекцией можно прочитать только пп. 10.1-10.3, 10.10-10.13. Оглавление Лекция 10. Функциональное и объектное программирование в JavaScript................................................................

Лекция 10. Функциональное и объектное программирование в JavaScript При первоначальном знакомстве с лекцией можно прочитать только пп. 10.1-10.3, 10.10-10.13. Оглавление Лекция 10. Функциональное и объектное программирование в JavaScript.............................................................. 1 10.1. Функции.............................................................................................................................................................. 2 10.2. Область видимости переменных................................................................................................................... 6 10.3. Замыкания и функции IIFE.............................................................................................................................. 9 10.4. Простейший модуль....................................................................................................................................... 11 10.5. Рекурсивные функции..................................................................................................................................... 13 10.6. Переопределение функций............................................................................................................................. 14 10.7. Hoisting.............................................................................................................................................................. 15 10.8. Передача параметров по значению и по ссылке........................................................................................ 16 10.9. Стрелочные функции..................................................................................................................................... 17 10.10. Объекты......................................................................................................................................................... 19 10.11. Вложенные объекты и массивы в объектах............................................................................................ 22 10.12. Проверка наличия и перебор методов и свойств.................................................................................... 24 10.13. Объекты в функциях.................................................................................................................................... 25 10.14. Конструкторы объектов............................................................................................................................ 26 10.15. Расширение объектов. Prototype................................................................................................................ 28 10.16. Инкапсуляция................................................................................................................................................ 29 10.17. Функция как объект. Методы call и apply................................................................................................. 30 10.18. Наследование................................................................................................................................................. 31 10.19. Ключевое слово this....................................................................................................................................... 33 10.20. Декомпозиция................................................................................................................................................ 36 10.21. Классы............................................................................................................................................................ 38 Задание к лабораторной работе 10.....................................................................Ошибка! Закладка не определена. Варианты задачи 1............................................................................................Ошибка! Закладка не определена. Варианты задачи 2............................................................................................Ошибка! Закладка не определена. Пример реализации задачи 1..........................................................................Ошибка! Закладка не определена. Пример реализации задачи 2..........................................................................Ошибка! Закладка не определена. 10.1. Функции Функции представляют собой набор инструкций, выполняющих определенное действие или вычисляющих определенное значение. Синтаксис определения функции: function имя_функции ([параметр [,...]]){ // Инструкции } Определение функции начинается с ключевого слова function, после которого следует имя функции. Наименование функции подчиняется тем же правилам, что и наименование переменной: оно может содержать только цифры, буквы, символы подчеркивания и доллара ($) и должно начинаться с буквы, символа подчеркивания или доллара. После имени функции в скобках идет перечисление параметров (аргументов). Даже если параметров у функции нет, то пустые скобки всё равно указываются. Затем в фигурных скобках следует тело функции, содержащее набор инструкций. Определим простейшую функцию: function display() { document.write("функция в JavaScript"); } Данная функция называется display(). Она не принимает никаких параметров и все, что она делает, это пишет на web-страницу строку. Однако простого определения функции еще недостаточно, чтобы она заработала. Её нужно ещё вызвать: function display() { document.write("функция в JavaScript"); } display(); Необязательно давать функциям определенное имя. Можно использовать анонимные функции: var display = function(){ // определение функции document.write("функция в JavaScript"); } display(); Фактически мы определяем переменную display и присваиваем ей ссылку на функцию. А затем по имени переменной функция вызывается. Также мы можем динамически присваивать функции для переменной: function goodMorning() { document.write("Доброе утро"); } function goodEvening() { document.write("Добрый вечер"); } var message = goodMorning; message(); // Доброе утро message = goodEvening; message(); // Добрый вечер Рассмотрим передачу параметров: function display (x) { // определение функции var z = x * x; document.write(x + " в квадрате равно " + z); } display (5); // вызов функции Функция display принимает один параметр - x. Поэтому при вызове функции мы можем передать для него значение, например, число 5, как в данном случае. Если функция принимает несколько параметров, то с помощью spread-оператора... (многоточие) мы можем передать набор значений для этих параметров из массива: function sum(a, b, c) { let d = a + b + c; console.log(d); } sum(1, 2, 3); let nums = [4, 5, 6]; sum(...nums); Во втором случае в функцию передается числа из массива nums. Но чтобы передавался не просто массив, как одно значение, а именно числа из этого массива, применяется spread-оператор... (многоточие). Функция может принимать множество параметров, но при этом часть или все параметры могут быть необязательными. Если для параметров не передается значение, то по умолчанию они имеют значение "undefined". function display(x, y) { if (y === undefined) y = 5; if (x === undefined) x = 8; let z = x * y; console.log(z); } display(); // 40 display(6); // 30 display(6, 4) // 24 Здесь функция display принимает два параметра. При вызове функции мы можем проверить их значения. При этом, вызывая функцию, необязательно передавать для этих параметров значения. Для проверки наличия значения параметров используется сравнение со значением undefined. Есть и другой способ определения значения для параметров по умолчанию: function display(x = 5, y = 10) { let z = x * y; console.log(z); } display(); // 50 display(6); // 60 display(6, 4) // 24 Если параметрам x и y не передаются значения, то они получаются в качестве значений числа 5 и 10 соответственно. Такой способ более лаконичен и интуитивен, чем сравнение с undefined. При этом значение параметра по умолчанию может быть производным, то есть, представлять собой выражение: function display (x = 5, y = 10 + x) { let z = x * y; console.log(z); } display(); // 75 display(6); // 96 display(6, 4) // 24 В данном случае значение параметра y зависит от значения x. При необходимости мы можем получить все переданные параметры через глобально доступный массив arguments: function display (){ var z = 1; for (var i=0; i x + y; let a = sum(4, 5); // 9 let b = sum(10, 5); // 15 В данном случае функция (x, y) => x + y осуществляет сложение двух чисел и присваивается переменной sum. Функция принимает два параметра - x и y. Ее тело составляет сложение значений этих параметров. И поскольку после стрелки фактически идет конкретное значение, которое представляет сумму чисел, то функция возвращает это значение. И мы можем через переменную sum вызвать данную функцию и получить ее результат в переменные a и b. Если после стрелки следует операция или выражение, которое возвращает значение, то это значение фактически возвращается из стрелочной функции. Но также в качестве тела функции может примяться выражение, которое ничего не возвращает и просто выполняет некоторое действие: let sum = (x, y) => console.log(x + y); sum(4, 5); // 9 sum(10, 5); // 15 В данном случае функция console.log() ничего не возвращает, и соответственно функция sum также не возвращает никакого результата. Если функция принимает один параметр, то скобки вокруг него можно опустить: var square = n => n * n; console.log(square(5)); // 25 console.log(square(6)); // 36 console.log(square(-7)); // 49 Если тело функции представляет набор выражений, то они заключаются в фигурные скобки: var square = n => { let result = n * n; return result; } console.log(square(5)); // 25 Для возвращения результата из функции в таком случае применяется стандартный оператор return. Особо следует остановиться на случае, когда стрелочная функция возвращает объект: let user = (userName, userAge) => ({name: userName, age: userAge}); let tom = user("Tom", 34); let bob = user("Bob", 25); console.log(tom.name, tom.age); // "Tom", 34 console.log(bob.name, bob.age); // "Bob", 25 Объект также определяется с помощью фигурных скобок, но при этом он заключается в круглые скобки. Если стрелочная функция не принимает никаких параметров, то ставятся пустые скобки: var hello = ()=> console.log("Hello World"); hello(); // Hello World hello(); // Hello World Формальное отличие стрелочных функций от function в том, что они не имеют своего указателя this. В стрелочных функциях указатель this получает значение на момент объявления функции, а в function он устанавливается во время вызова, и может быть утерян в зависимости от контекста вызова. Также стрелочные функции не имеют своего прототипа, соответственно, не могут использоваться в качестве конструктора. 10.10. Объекты Объектно-ориентированное программирование на сегодняшний день является одной из господствующих парадигм в разработке приложений, и в JavaScript мы также можем использовать все преимущества ООП. В то же время применительно к JavaScript объектно-ориентированное программирование имеет некоторые особенности. В прошлых темах мы работали с примитивными данными - числами, строками, но данные не всегда представляют примитивные типы. Например, если в нашей программе нам надо описать сущность человека, у которого есть имя, возраст, пол и так далее, то естественно мы не сможем представить сущность человека в виде числа или строки. Нам потребуется несколько строк или чисел, чтобы должным образом описать человека. В этом плане человек будет выступать как сложная комплексная структура, у которого будут отдельные свойства - возраст, рост, имя, фамилия и т.д. Для работы с подобными структурами в JavaScript используются объекты. Каждый объект может хранить свойства, которые описывают его состояние, и методы, которые описывают его поведение. Есть несколько способов создания нового объекта. Первый способ заключается в использовании конструктора Object: var user = new Object(); В данном случае объект называется user. Он определяется также, как и любая обычная переменная с помощью ключевого слова var. Выражение new Object() представляет вызов конструктора - функции, создающей новый объект. Для вызова конструктора применяется оператор new. Вызов конструктора фактически напоминает вызов обычной функции. Второй способ создания объекта представляет использование фигурных скобок: var user = {}; На сегодняшний день более распространенным является второй способ. После создания объекта мы можем определить в нем свойства. Чтобы определить свойство, надо после названия объекта через точку указать имя свойства и присвоить ему значение: var user = {}; user.name = "Tom"; user.age = 26; В данном случае объявляются два свойства name и age, которым присваиваются соответствующие значения. После этого мы можем использовать эти свойства, например, вывести их значения в консоли: console.log(user.name); console.log(user.age); Также можно определить свойства при определении объекта: var user = { name: "Tom", age: 26 }; В этом случае для присвоения значения свойству используется символ двоеточия, а после определения свойства ставится запятая (а не точка с запятой). Кроме того, доступен сокращенный способ определения свойств: var name = "Tom"; var age = 34; var user = { name, age }; console.log (user.name); // Tom console.log (user.age); // 34 В данном случае названия переменных также являются и названиями свойств объекта. И таким образом можно создавать более сложные конструкции: var name = "Tom"; var age = 34; var user = { name, age }; var teacher = { user, course: "JavaScript" }; console.log (teacher.user); // {name: "Tom", age: 34} console.log (teacher.course); // JavaScript Методы объекта определяют его поведение или действия, которые он производит. Методы представляют собой функции. Например, определим метод, который бы выводил имя и возраст человека: var user = {}; user.name = "Tom"; user.age = 26; user.display = function() { console.log(user.name); console.log(user.age); }; // вызов метода user.display(); Как и в случае с функциями методы сначала определяются, а потом уже вызываются. Также методы могут определяться непосредственно при определении объекта: var user = { name: "Tom", age: 26, display: function() { console.log(this.name); console.log(this.age); } }; Как и в случае со свойствами, методу присваивается ссылка на функцию с помощью знака двоеточия. Чтобы обратиться к свойствам или методам объекта внутри этого объекта, используется ключевое слово this. Оно означает ссылку на текущий объект. Также можно использовать сокращенный способ определения методов, когда двоеточие и слово function опускаются: var user = { name: "Tom", age: 26, display() { console.log(this.name, this.age); }, move(place) { console.log(this.name, "goes to", place); } }; user.display(); // Tom 26 user.move("the shop"); // Tom goes to the shop Существует также альтернативный способ определения свойств и методов с помощью синтаксиса массивов: var user = {}; user["name"] = "Tom"; user["age"] = 26; user["display"] = function() { console.log(user.name); console.log(user.age); }; // вызов метода user["display"](); Название каждого свойства или метода заключается в кавычки и в квадратные скобки, затем им также присваивается значение. Например, user["age"] = 26. При обращении к этим свойствам и методам можно использовать либо нотацию точки (user.name), либо обращаться так: user["name"] Также следует отметить, что названия свойств и методов объекта всегда представляют строки. То есть мы могли предыдущее определение объекта переписать так: var user = { "name": "Tom", "age": 26, "display": function(){ console.log(user.name); console.log(user.age); } }; // вызов метода user.display(); С одной стороны, разницы никакой нет между двумя определениями. С другой стороны, бывают случаи, где заключение названия в строку могут помочь. Например, если название свойства состоит из двух слов, разделенных пробелом: var user = { name: "Tom", age: 26, "full name": "Tom Johns", "display info": function(){ console.log(user.name); console.log(user.age); } }; console.log(user["full name"]); user["display info"](); Только в этом случае для обращения к подобным свойствам и методам мы должны использовать синтаксис массивов. Выше мы посмотрели, как можно динамически добавлять новые свойства к объекту. Однако также мы можем удалять свойства и методы с помощью оператора delete. И как и в случае с добавлением мы можем удалять свойства двумя способами. Первый способ - использование нотации точки: delete объект.свойство Либо использовать синтаксис массивов: delete объект["свойство"] Например, удалим свойство: var user = {}; user.name = "Tom"; user.age = 26; user.display = function(){ console.log(user.name); console.log(user.age); }; console.log(user.name); // Tom delete user.name; // удаляем свойство // альтернативный вариант // delete user["name"]; console.log(user.name); // undefined После удаления свойство будет не определено, поэтому при попытке обращения к нему, программа вернет значение undefined. 10.11. Вложенные объекты и массивы в объектах Одни объекты могут содержать в качестве свойств другие объекты. Например, есть объект страны, у которой можно выделить ряд свойств. Одно из этих свойств может представлять столицу. Но у столицы мы также можем выделить свои свойства, например, название, численность населения, год основания: var country = { name: "Германия", language: "немецкий", capital:{ name: "Берлин", population: 3375000, year: 1237 } }; console.log("Столица: " + country.capital.name); // Берлин console.log("Население: " + country["capital"]["population"]); // 3375000 console.log("Год основания: " + country.capital["year"]); // 1237 Для доступа к свойствам таких вложенных объектов мы можем использовать стандартную нотацию точки: country.capital.name Либо обращаться к ним как к элементам массивов: country["capital"]["population"] Также возможен смешанный вид обращения: country.capital["year"] В качестве свойств также могут использоваться массивы, в том числе массивы других объектов: var country = { name: "Швейцария", languages: ["немецкий", "французский", "итальянский"], capital:{ name: "Берн", population: 126598 }, cities: [ { name: "Цюрих", population: 378884 }, { name: "Женева", population: 188634 }, { name: "Базель", population: 164937 } ] }; // вывод всех элементов из country.languages document.write("Официальные языки Швейцарии"); for (var i=0; i < country.languages.length; i++) document.write(country.languages[i] + ""); // вывод всех элементов из country.cities document.write("Города Швейцарии"); for (var i=0; i < country.cities.length; i++) document.write(country.cities[i].name + ""); В объекте country имеется свойство languages, содержащее массив строк, а также свойство cities, хранящее массив однотипных объектов. С этими массивами мы можем работать так же, как и с любыми другими, например, перебрать с помощью цикла for. При переборе массива объектов каждый текущий элемент будет представлять отдельный объект, поэтому мы можем обратиться к его свойствам и методам: country.cities[i].name В итоге браузер выведет содержимое этих массивов: 10.12. Проверка наличия и перебор методов и свойств При динамическом определении в объекте новых свойств и методов перед их использованием бывает важно проверить, а есть ли уже такие методы и свойства. Для этого в JavaScript может использоваться оператор in: var user = {}; user.name = "Tom"; user.age = 26; user.display = function(){ console.log(user.name); console.log(user.age); }; var hasNameProp = "name" in user; console.log(hasNameProp); // true - свойство name есть в user var hasWeightProp = "weight" in user; console.log(hasWeightProp); //false - в user нет свойства или метода под названием weight Оператор in имеет следующий синтаксис: "свойство|метод" in объект - в кавычках идет название свойства или метода, а после in - название объекта. Если свойство или метод с подобным именем имеется, то оператор возвращает true. Если нет - то возвращается false. Альтернативный способ заключается на значение undefined. Если свойство или метод равен undefined, то эти свойство или метод не определены: var hasNameProp = user.name!==undefined; console.log(hasNameProp); // true var hasWeightProp = user.weight!==undefined; console.log(hasWeightProp); // false И так как объекты представляют тип Object, а значит, имеет все его методы и свойства, то объекты также могут использовать метод hasOwnProperty(), который определен в типе Object: var hasNameProp = user.hasOwnProperty('name'); console.log(hasNameProp); // true var hasDisplayProp = user.hasOwnProperty('display'); console.log(hasDisplayProp); // true var hasWeightProp = user.hasOwnProperty('weight'); console.log(hasWeightProp); // false С помощью цикла for мы можем перебрать объект как обычный массив и получить все его свойства и методы и их значения: var user = {}; user.name = "Tom"; user.age = 26; user.display = function(){ console.log(user.name); console.log(user.age); }; for(var key in user) { console.log(key + " : " + user[key]); } И при запуске консоль браузера отобразит следующий вывод: name : Tom age : 26 display : function (){ console.log(user.name); console.log(user.age); } 10.13. Объекты в функциях Функции могут возвращать значения. Но эти значения не обязательно должны представлять примитивные данные - числа, строки, но также могут быть сложными объектами. Например, вынесем создание объекта user в отдельную функцию: function createUser(pName, pAge) { return { name: pName, age: pAge, displayInfo: function() { document.write("Имя: " + this.name + " возраст: " + this.age + ""); } }; }; var tom = createUser("Tom", 26); tom.displayInfo(); var alice = createUser("Alice", 24); alice.displayInfo(); Здесь функция createUser() получает значения pName и pAge и по ним создает новый объект, который является возвращаемым результатом. Преимуществом вынесения создания объекта в функцию является то, что далее мы можем создать несколько однотипных объектов с разными значениями. Кроме того объект может передаваться в качестве параметра в функцию: function createUser(pName, pAge) { return { name: pName, age: pAge, displayInfo: function() { document.write ("Имя: " + this.name + " возраст: " + this.age + ""); }, driveCar: function(car){ document.write (this.name + " ведет машину " + car.name + ""); } }; }; function createCar(mName, mYear){ return { name: mName, year: mYear }; }; var tom = createUser("Том", 26); tom.displayInfo(); var bentley = createCar("Бентли", 2004); tom.driveCar(bentley); Здесь используются две функции для создания пользователей и объекта машины. Метод driveCar() объекта user в качестве параметра принимает объект car. В итоге браузер нам выведет: Имя: Том возраст: 26 Том ведет машину Бентли 10.14. Конструкторы объектов Кроме создания новых объектов JavaScript предоставляет нам возможность создавать новые типы объектов с помощью конструкторов. Так, одним из способов создания объекта является применение конструктора типа Object: var tom = new Object(); После создания переменной tom она будет вести себя как объект типа Object. Конструктор позволяет определить новый тип объекта. Тип представляет собой абстрактное описание или шаблон объекта. Можно еще провести следующую аналогию. У нас у всех есть некоторое представление о человеке - наличие двух рук, двух ног, головы, пищеварительной, нервной системы и т.д. Есть некоторый шаблон - этот шаблон можно назвать типом. Реально же существующий человек является объектом этого типа. Определение типа может состоять из функции конструктора, методов и свойств. Для начала определим конструктор: function User(pName, pAge) { this.name = pName; this.age = pAge; this.displayInfo = function() { document.write ("Имя: " + this.name + "; возраст: " + this.age + ""); }; } Конструктор - это обычная функция за тем исключением, что в ней мы можем установить свойства и методы. Для установки свойств и методов используется ключевое слово this: this.name = pName; В данном случае устанавливаются два свойства name и age и один метод displayInfo. Как правило, названия конструкторов, в отличие от названий обычных функций начинаются с большой буквы. После этого в программе мы можем определить объект типа User и использовать его свойства и методы: var tom = new User("Том", 26); console.log(tom.name); // Том tom.displayInfo(); Чтобы вызвать конструктор, то есть создать объект типа User, надо использовать ключевое слово new. Подобным образом мы можем определить и другие типы и использовать их вместе: // конструктор типа Car function Car(mName, mYear){ this.name = mName; this.year = mYear; this.getCarInfo = function() { document.write ("Модель: " + this.name + " Год выпуска: " + this.year + ""); }; }; // конструктор типа User function User(pName, pAge) { this.name = pName; this.age = pAge; this.driveCar = function(car) { document.write (this.name + " ведет машину " + car.name + ""); }; this.displayInfo = function(){ document.write ("Имя: " + this.name + "; возраст: " + this.age + ""); }; }; var tom = new User("Том", 26); tom.displayInfo(); var bentley = new Car ("Бентли", 2004); tom.driveCar (bentley); Оператор instanceof позволяет проверить, с помощью какого конструктора создан объект. Если объект создан с помощью определенного конструктора, то оператор возвращает true: var tom = new User("Том", 26); var isUser = tom instanceof User; var isCar = tom instanceof Car; console.log(isUser); // true console.log(isCar); // false 10.15. Расширение объектов. Prototype Кроме непосредственного определения свойств и методов в конструкторе мы также можем использовать свойство prototype. Каждая функция имеет свойство prototype, представляющее прототип функции. То есть свойство User.prototype представляет прототип объектов User. И любые свойства и методы, которые будут определены в User.prototype, будут общими для всех объектов User. Например, после определения объекта User нам потребовалось добавить к нему метод и свойство: function User(pName, pAge) { this.name = pName; this.age = pAge; this.displayInfo = function() { document.write ("Имя: " + this.name + "; возраст: " + this.age + ""); }; }; User.prototype.hello = function(){ document.write(this.name + " говорит: 'Привет!'"); }; User.prototype.maxAge = 110; var tom = new User("Том", 26); tom.hello(); var john = new User("Джон", 28); john.hello(); console.log(tom.maxAge); // 110 console.log(john.maxAge); // 110 Здесь добавлены метод hello и свойство maxAge, и каждый объект User сможет их использовать. Но важно заметить, что значение свойства maxAge будет одно и то же для всех объектов, это разделяемое статическое свойство. В отличие, скажем, от свойства this.name, которое хранит значение для определенного объекта. В то же время мы можем определить в объекте свойство, которое будет назваться так же, как и свойство прототипа. В этом случае собственное свойство объекта будет иметь приоритет перед свойством прототипа: User.prototype.maxAge = 110; var tom = new User("Том", 26); var john = new User("Джон", 28); tom.maxAge = 99; console.log(tom.maxAge); // 99 console.log(john.maxAge); // 110 И при обращении к свойству maxAge JavaScript сначала ищет это свойство среди свойств объекта, и если оно не было найдено, тогда обращается к свойствам прототипа. То же самое касается и методов. 10.16. Инкапсуляция Инкапсуляция является одним из ключевых понятий объектно-ориентированного программирования и представляет сокрытие состояния объекта от прямого доступа извне. По умолчанию все свойства объектов являются публичными, общедоступными, и мы к ним можем обратиться из любого места программы. function User (pName, pAge) { this.name = pName; this.age = pAge; this.displayInfo = function() { document.write ("Имя: " + this.name + "; возраст: " + this.age); }; }; var tom = new User("Том", 26); tom.name=34; console.log(tom.name); Но мы можем их скрыть от доступа извне, сделав свойства локальными переменными: function User (name, age) { this.name = name; var _age = age; this.displayInfo = function() { document.write ("Имя: " + this.name + "; возраст: " + _age + ""); }; this.getAge = function() { return _age; } this.setAge = function(age) { if (typeof age === "number" && age >0 && ageconsole.log(this.title, course)) } } school.printCourses(); Контекстом для стрелочной функции в данном случае будет выступать контекст объекта school. Соответственно, нам недо определять дополнительные переменные для передачи данных в функцию. 10.20. Декомпозиция Декомпозиция (destructuring) позволяет извлечь из объекта отдельные значения в переменные: let user = { name: "Tom", age: 24, phone: "+367438787", email: "[email protected]" }; let {name, email} = user; console.log(name); // Tom console.log(email); // [email protected] Для декомпозиции объекта переменные помещаются в фигурные скобки и им присваивается объект. Сопоставление между свойствами объекта и переменными идет по имени. Мы можем указать, что мы хотим получить значения свойств объекта в переменные с другим именем: let user = { name: "Tom", age: 24, phone: "+367438787", email: "[email protected]" }; let {name: userName, email: mailAddress} = user; console.log (userName); // Tom console.log (mailAddress); // [email protected] В данном случае свойство name сопоставляется с переменной userName, а поле email - с переменной mailAddress. Также можно декомпозировать массивы: let users = ["Tom", "Sam", "Bob"]; let [a, b, c] = users; console.log(a); // Tom console.log(b); // Sam console.log(c); // Bob Для декомпозиции массива переменные помещаются в квадратные скобки и последовательно получают значения элементов массива. При этом, мы можем пропустить ряд элементов массива, оставив вместо имен переменных пропуски: let users = ["Tom", "Sam", "Bob", "Ann", "Alice", "Kate"]; let [first,,,,fifth] = users; console.log (first); // Tom console.log (fifth); // Alice Выражение first,,,,fifth указывает, что мы хотим получить первый элемент массива в переменную first, затем пропустить три элемента и получить пятый элемент в переменную fifth. Подобным образом можно получить, например, второй и четвертый элементы: let users = ["Tom", "Sam", "Bob", "Ann", "Alice", "Kate"]; let [,second,,forth] = users; console.log(second); // Sam console.log(forth); // Ann Можно совместить получение данных из массива и объекта: let people = [ {name: "Tom", age: 34}, {name: "Bob", age: 23}, {name: "Sam", age: 32} ]; let [,{name}] = people; console.log(name); // Bob В данном случае получаем значение свойства name второго объекта в массиве. Если в функцию в качестве параметра передается массив или объект, то его также можно подобным образом декомпозировать: function display({name:userName, age:userAge}){ console.log(userName, userAge); } function sum([a, b, c]){ var result = a + b + c; console.log(result); } let user = {name:"Alice", age:33, email: "[email protected]"}; let numbers = [3, 5, 7, 8]; display(user); // Alice 33 sum(numbers); // 15 10.21. Классы С внедрением стандарта ES2015 (ES6) в JavaScript появился новый способ определения объектов - с помощью классов. Класс представляет описание объекта, его состояния и поведения, а объект является конкретным воплощением или экземпляром класса. Для определения класса используется ключевое слово class: class Person { } После слова class идет название класса (в данном случае класс называется Person), и затем в фигурных скобках определяется тело класса. Также можно определить анонимный класс и присвоить его переменной: let Person = class {} После этого мы можем создать объекты класса с помощью конструктора: class Person {} let tom = new Person(); let bob = new Person(); Для создания объекта с помощью конструктора сначала ставится ключевое слово new. Затем собственно идет вызов конструктора - по сути вызов функции по имени класса. По умолчанию классы имеют один конструктор без параметров. Поэтому в данном случае при вызове конструктора в него не передается никаких аргументов. Также мы можем определить в классе свои конструкторы. Также класс может содержать свойства и методы: class Person{ constructor(name, age){ this.name = name; this.age = age; } display(){ console.log(this.name, this.age); } } let tom = new Person("Tom", 34); tom.display(); // Tom 34 console.log(tom.name); // Tom Конструктор определяется с помощью метода с именем constructor. По сути это обычный метод, который может принимать параметры. Основная цель конструктора - инициализировать объект начальными данными. В данном случае конструктору передаются два значения - для имени и возраста пользователя. Для хранения состояния в классе определяются свойства. Для их определения используется ключевое слово this. В данном случае в классе два свойства: name и age. Поведение класса определяют методы. В данном случае определен метод display(), который выводит значения свойств на консоль. Поскольку мы определили конструктор, который принимает два параметра, то соответственно мы можем передать в конструктор два значения для инициализации объекта: new Person("Tom", 34). Одни классы могут наследоваться от других. Наследование позволяет сократить объем кода в классах-наследниках. Например, определим следующие классы: class Person{ constructor(name, age){ this.name = name; this.age = age; } display(){ console.log(this.name, this.age); } } class Employee extends Person{ constructor(name, age, company){ super(name, age); this.company = company; } display(){ super.display(); console.log("Employee in", this.company); } work(){ console.log(this.name, "is hard working"); } } let tom = new Person("Tom", 34); let bob = new Employee("Bob", 36, "Google"); tom.display(); bob.display(); bob.work(); Для наследования одного класса от другого в определении класса применяется оператор extends, после которого идет название базового класса. То есть в данном случае класс Employee наследуется от класса Person. Класс Person еще называется базовым классом, классом-родителем, суперклассом, а класс Employee - классом-наследником, подклассом, производным классом. Производный класс, как и базовый, может определять конструкторы, свойства, методы. Вместе с тем с помощью слова super производный класс может ссылаться на функционал, определенный в базовом. Например, в конструкторе Employee можно вручную не устанавливать свойства name и age, а с помощью выражения super (name, age); вызвать конструктор базового класса и тем самым передать работу по установке этих свойств базовому классу. Подобным образом в методе display в классе Employee через вызов super.display() можно обратиться к реализации метода display класса Person. Консольный вывод программы: Tom 34 Bob 36 Employee in Google Bob is hard working Статические методы вызываются для всего класса в целом, а не для отдельного объекта. Для их определения применяется оператор static. Например: class Person{ constructor(name, age){ this.name = name; this.age = age; } static nameToUpper(person){ return person.name.toUpperCase(); } display(){ console.log(this.name, this.age); } } let tom = new Person("Tom Soyer", 34); let personName = Person.nameToUpper(tom); console.log(personName); // TOM SOYER В данном случае определен статический метод nameToUpper(). В качестве параметра он принимает объект Person и переводит его имя в верхний регистр. Поскольку статический метод относится классу в целом, а не к объекту, то мы не можем использовать в нем ключевое слово this и через него обращаться к свойствам объекта.

Use Quizgecko on...
Browser
Browser