Translate

Поиск по этому блогу

среда, 19 сентября 2018 г.

ES6: Классы (IX).

Классы в ES6

Классы являются основой объектно-ориентированное программирование но не в JavaScript.



Все материалы по ES6


В объектно-ориентированное программирование наследование основано на прототипах объектов, а не на классах.

Если вы когда-нибудь писали код на Java Script имитируя классы, ты уверен согласитесь синтаксис не самый элегантный и простой.

С появлением es6 JavaScript наконец-то добавлена поддержка классов. Новый синтаксис не вводит новую объектно-ориентированная модель наследования, внутри используется всё те же прототипы.

Синтаксис классов это так называемый syntactic Sugar или синтаксический сахар, который призван немного подсластить, то есть упростить работу с классами и наследованием в JavaScript.

Сегодня мы рассмотрим новый синтаксис классов, а в следующем посте - наследование.

Первое, что мы сделаем, это запустим скрипт Babel, который будет следить за файлами и при их изменении создавать свежие версии.

Откроем папку проекта в командной строке (КС). Вводим команду:

npm run watch


И нажать Enter

В папке src создадим файл classes.js и сразу укажу его в файле index.html

<script src="src/classes.js"></script>

HTML последние версии браузеров поддерживает класс без транспиляции, и мой браузер входит в их число, но тем не менее в конце, мы посмотрим на транспилированный код.

Начнем сначала а именно создание классов.

Создание классов

Класс это формы или шаблон по которому создаются объекты. Классы в JavaScript определяют свойства, то есть какой будет объект и методы - что этот объект будет делать. При создание классов используется ключевое слово class, после которого указывается имя класса. В качестве примера я создам класс названием Task - или задача. Тело класса находится в фигурных скобках и в нём будут находиться члены класса, методы и свойства. А в консоли мы посмотрим на класс используя оператор typeof.


class Task {

};

console.log( typeof Task );





В консоли мы видим function. Это означает, что классы это функции, которые создают объекты. Теперь перейдем к созданию объектов.

Объекты

Объект - это экземпляр или представитель класса.

То есть объект созданный по шаблону с определёнными свойствами и методами указанными в классе. Для создания объектов мы используем ключевое слово new.

После класса мы объявим переменную task с маленькой буквы и в качестве значения укажу new Task То есть мы вызываем функцию Task передний ней ключевое слово - new.

Теперь, давайте в консоли посмотрим на тип переменной task и также проверим является ли task, представителем класса Task -с большой буквы.

Мы можем это проверить используя оператор instanceof.


class Task {

};

let task = new Task();

console.log( typeof task );
console.log( task instanceof Task );





Мы видим, что переменная тоски является объектом или точнее, содержит ссылку на объект, и этот объект является представителем класса.

Конструктор.

Конструктор - это особый метод, который вызывается в момент создания объекта.

То есть когда мы используем ключевое слово new Он создаёт свойства и инициализирует. То есть подготавливает объект к использованию.

В классе может быть только один конструктор!

Если мы укажем несколько, то получим ошибку.

Если же мне укажем конструктор вообще-то JavaScript создаст пустой конструктор.

Для того чтобы объявить конструктор в теле класса пишем constructor() {} Внутри конструктора я выведу сообщение о том что происходит создание задачи.


class Task {
 constructor() {
  console.log('Происходит создание задачи');
 }
};

let task = new Task();

console.log( typeof task );
console.log( task instanceof Task );



Давайте посмотрим на результат браузере.



и мы увидим сообщение о создании задачи

тем самым мы увидели, что конструктор сработал.

Свойства

Свойства - это характеристики объекта.

Они описывают какой объект или что у него имеется.

Свойство указывается в конструкторе. Таким образом каждый представитель класса имеет эти свойства.

Для того чтобы создать свойства у объекта, в конструкторе используется ключевое слово this, которое указывает на объект, который мы создаем.

Например у класса Task будет свойства title или заголовок, который будет содержать заголовок задачи.

Для того, чтобы указать свойство я напишу слово this. Дальше названия свойства title и в принципе всё, но мы можем указать значение. И в качестве значения давайте укажем

"Выучить JavaScript"


class Task {
 constructor() {
  this.title = "Выучить JavaScript";
  console.log('Происходит создание задачи');
 }
};

let task = new Task();

console.log( typeof task );
console.log( task.title );



и в консоли давайте выведем значение title.



Конструктор может принимать параметры, которые мы можем указать в качестве аргументов при создании нового объекта. Давайте скопируем название задачи из конструктора и вставим его между круглыми скобками.

let task = new Task("Выучить JavaScript");

Далее, в конструкторе нам необходимо указать параметр title.

И давайте присвоим ему значение по умолчанию пустую строку.

И свойству при присвоении - значение параметра title.


class Task {
 constructor( title = '' ) {
  this.title = title;
  console.log('Происходит создание задачи');
 }
};

let task = new Task("Выучить JavaScript");

console.log( typeof task );
console.log( task.title );



И в консоли мы видим тот же самый результат.

Теперь мы можем создать вторую задачу и в качестве заголовка указать что-нибудь другое - номер "выучить ES6".


class Task {
 constructor( title = '' ) {
  this.title = title;
  console.log('Происходит создание задачи');
 }
};

let task = new Task("Выучить JavaScript");
let task2 = new Task("Выучить ES6");

console.log( typeof task );
console.log( task.title );
console.log( task2.title );





Давайте добавим классу Task ещё одно свойство которое будет называться done, в котором будет указываться выполнена задача или нет.

По умолчанию мы поставим false. То есть задачи по умолчанию будет не выполнена.

При создании объекта принимать аргумент done мы не будем.

Одно маленькое замечание - свойства указывается только в конструкторе! Если у вас есть опыт работы с другими языками и такими как Java, C++ или C# в которых свойство указывает отдельно от конструктора, а в конструкторе инициализируется, то в джаваскрипт свойство указываются исключительно в конструкторе!




Так как на фото выше мы сделать не можем!

Или убрать слово let и var или const всё это не будет работать!

Насколько я знаю это исправят в следующей версии JvaScript.

Далее мы рассмотрим создание методов методы.

Методы.

Методы это то что объект умеет делать, то есть его возможности.

По сути это функции, которые в классе называются методами.

Давайте добавим классу Task метод complete(){}, с помощью которого мы укажем что задача выполнена.

Чтобы указать метод мы пишем названия метода, после чего пара круглых скобок за ними пару фигурных скобок. В теле метода мы напишем this.done = true;

Заметьте что между методами в классах не ставится, если я поставлю то мы получим ошибку


И для того чтобы видеть результат - console.log(`Задача "${this.title}" выполнена!`);


class Task {
 constructor( title = '' ) {
  this.title = title;
                this.done = false;
  console.log('Происходит создание задачи');
 }
  complete() {
  this.done = true;
  console.log(`Задача "${this.title}" выполнена!`);
 }
};

let task = new Task("Выучить JavaScript");
let task2 = new Task("Выучить ES6");

console.log( typeof task );
console.log( task.title );
console.log( task2.title );

task2.complete();





В самом сообщении воспользуюсь шаблоны строкой.

Далее, придём к статическим свойствам и методам

Статические свойства и методы



Статические свойства.



Статические свойства - это свойства которые принадлежат самому классу, а не объектам, созданным на его основе.

Статические свойства часто используются для хранения вспомогательной информации и в отличие от многих других языков, например Java, C++ или C#, мы не можем Объявлять статические свойства используют ключевое слово static.

Если мы попробую написать будет ошибка.



Так что же делать если статическая переменная мы не можем объявить о самом классе?

В самом деле это делается очень просто.

После объявления класса, мы пишем название класса и далее, так как функции в JavaScript являются такими же объектами, как и всё остальное, мы можем просто присвоить свойство.

И сразу укажем значение.

И в конструкторе при создании задачи мы давали Task.count += 1;

И после того как мы создали задачу...

class Task {
 constructor( title = '' ) {
  this.title = title;
  this.done = false;
  Task.count += 1;
  console.log('Происходит создание задачи');
 }
  complete() {
  this.done = true;
  console.log(`Задача "${this.title}" выполнена!`);
 }
};

Task.count = 0; 

let task = new Task("Выучить JavaScript");
let task2 = new Task("Выучить ES6");


console.log( task.title );
console.log( task2.title );

console.log( Task.count );
task2.complete();



Давайте вывезем значение в консоль. Оно должно равняться двум.



И действительно, мы видим 2.

Статические методы.

Статические методы это методы которые принадлежат самому классу, а не объектам созданным на его основе.

Статические методы часто используются для создания вспомогательных функций.

Давайте добавим Task статический метод.

Для того чтобы создать статический метод убежим ключевое слово static и дальше название метода.

Статический метод getDefaultTitle() с помощью которого мы сможем получить значение заголовка по умолчанию если тот не был передан. Поэтому в теле метода мы просто вернем слово "Задача".


 static getDefaultTitle() {
   return "Задача";
 }



теперь в конструкторе мы можем указать ->


class Task {
 constructor( title = Task.getDefaultTitle() ) {
  this.title = title;
  this.done = false;
  Task.count += 1;
  console.log('Происходит создание задачи');
 }
 get done() {
  return this.done === true ? 'Выполнено' : 'Не выполнено';
 }
 complete() {
  this.done = true;
  console.log(`Задача "${this.title}" выполнена!`);
 }
 static getDefaultTitle() {
   return "Задача";
 }
};

Task.count = 0; 

let task = new Task("Выучить JavaScript");
let task2 = new Task("Выучить ES6");
let task3 = new Task();

console.log( task.title );
console.log( task2.title );
console.log( task3.title );

console.log( Task.count );
task2.complete();



Давайте создадим задачу 3 без аргументов посмотрим на результат.



И мы видим что заголовок задачи 3 просто задача.

Если мы попытаемся вызвать метод .getDefaultTitle() у образца объекта которые мы сохранили в переменной task или task2 - не важно, то мы получим ошибку!

Давайте попробуем так - task.getDefaultTitle();

Мы получим ошибку Uncaught TypeError: task.getDefaultTitle is not a function.То есть у объектов task этого метода нет!

Единственный способ получить к нему доступ - использовать название самого класса!

У классов, помимо свойство методов можно добавить особые свойства get и set.

Особые свойства get и set.

Особые свойства get и set еще называются геттер и сеттер которые внутри класса выглядит ведут себя как методы а снаружи выглядит и ведут себя как свойства.

эти свойства - методы позволяют получить доступ и присвоить значение "настоящим свойствам объекта". То есть выступать в роли фильтра.

Давайте добавим свойства get и set классу - Task.

Для начала я немного почищу код. Удалю все созданные объекты и их выводы, кроме одного - task.

Итак начнем.

Get или гетер.
Если вывести в консоль значения console.log(task.done); то мы увидим false.



И если задача была бы выполнена тогда true.

Эти значения не совсем понятны простым пользователям. Было бы неплохо если бы при обращении к свойствам появлялось понятное сообщение.

Эту проблему можем решить используя свойство Get.

Давайте добавим классу Task это свойство.

Для этого в классе после конструктора я напишу слова get далее - название done, пару кругу скобок и пару фигуры скобок. Очень похоже на метод.

Но на самом деле это и есть метод.

Свойство get связывает свойства объекта с функцией, которая будет вызываться при обращении к этому свойству или методу.

В теле метода мы вернём строку в соответствии со значением свойства done.

Если done будет равняться true, то мы вернем одно значение если false то другое.

Давайте посмотрим на результат и мы увидим ошибку.



Которая говорит нам о том что не удалось указать свойство get .

Дело в том что название свойств Get и Set не должны совпадать с названием основных свойств объекта!

В нашем примере объявляя свойство get done() мы перезаписываемый значение done которое изначально указанно в конструкторе.

Есть несколько способов решить эту проблему и все они сводятся к переименование названий.

В других языках, например C#, названия личных свойств, там они называются полями, пишется с маленькой буквы, а публичных свойств с большой.

В JavaScript не принято называть свойства или метода заглавные буквы.

Также JavaScript свойства и методы в классах не делятся на личные и публичные.

Они всегда публичные!

И чтобы решить эту проблему, перед названием свойства методов которые мы хотим скрыть, часто ставят нижнее подчеркивание.

Давайте перед свойством done поставить нижнее подчеркивание.

this._done = false;

Это не означает что мы скрыли свойство или метод. К ним также легко получить доступ, но теперь хотя бы понятно что эти свойства личные.


class Task {
 constructor( title = Task.getDefaultTitle() ) {
  this.title = title;
  this._done = false;
  Task.count += 1;
  console.log('Происходит создание задачи');
 }
 get done() {
  return this._done === true ? 'Выполнено' : 'Не выполнено';
 }
  complete() {
  this.done = true;
  console.log(`Задача "${this.title}" выполнена!`);
 }
  static getDefaultTitle() {
   return "Задача";
 }
};

Task.count = 0; 

let task = new Task("Выучить JavaScript");
console.log(task.done, task._done);





Давайте попробуем выполнить задачу


task.complete();
console.log(task.done, task._done);



И ещё раз посмотрим.

И мы получили ошибку!



Это произошло потому что мы объявили свойство get но в методе .complete() мы присваиваем this.done значение true, но при этом свойства set мы не указали.


  complete() {
  this.done = true;
  console.log(`Задача "${this.title}" выполнена!`);
 }



Давайте добавим классу Task свойство set.

Свойство set
. Для этого после get я напишу set дальше название свойства.

Отличие set от get заключается в том что set принимает параметр ,который мы можем присвоить свойству, предварительно проверив этот параметр.

Вы можете назвать его как угодно но чаще всего его называют value.

И в теле метода мы проверим наличие значения value и Является ли это значение типом boolean. Если мы прошли проверку это свойство мы присвоим this._done.

Если же мы проверку не прошли то в консоли мы выдадим ошибку.


class Task {
 constructor( title = Task.getDefaultTitle() ) {
  this.title = title;
  this._done = false;
  Task.count += 1;
  console.log('Происходит создание задачи');
 }
 get done() {
  return this._done === true ? 'Выполнено' : 'Не выполнено';
 }
 set done(value) {
  if(value!== undefined && typeof value === 'boolean') {
   this._done = value;
  } else {
   console.error("Ошибка! Укажите значение true или false.");
  }
 }
  complete() {
  this.done = true;
  console.log(`Задача "${this.title}" выполнена!`);
 }
  static getDefaultTitle() {
   return "Задача";
 }
};

Task.count = 0; 

let task = new Task("Выучить JavaScript");
console.log(task.done, task._done);
task.complete();
console.log(task.done, task._done);



Давайте посмотрим на результат и мы видим что задача успешно выполнена!



Давайте попробуем присвоить, допустим Один.


  complete() {
  this.done = 1;
  console.log(`Задача "${this.title}" выполнена!`);
 }



И мы видим сообщение об ошибке.

О том что мы указали неверные значения.



Свойств можем указать сколько угодно.

В нашем примере мы можем переделать свойств title для того чтобы она использовала get и set. нам даже не обязательно иметь внутреннее свойство для того чтобы воспользоваться get и set.

Тем самым мы получим так называемая псевдо-свойства.

У классов, также как у объектов в ES6, название свойств методов может быть вычислено динамически, используя новый синтаксис - квадратные скобки.

У нас в конце-концов получился вполне себе полноценный класс.

И напоследок Давайте взглянем на то что сгенерировал Babel.


'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Task = function () {
 function Task() {
  var title = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Task.getDefaultTitle();

  _classCallCheck(this, Task);

  this.title = title;
  this._done = false;
  Task.count += 1;
  console.log('Происходит создание задачи');
 }

 _createClass(Task, [{
  key: 'complete',
  value: function complete() {
   this.done = 1;
   console.log('\u0417\u0430\u0434\u0430\u0447\u0430 "' + this.title + '" \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0430!');
  }
 }, {
  key: 'done',
  get: function get() {
   return this._done === true ? 'Выполнено' : 'Не выполнено';
  },
  set: function set(value) {
   if (value !== undefined && typeof value === 'boolean') {
    this._done = value;
   } else {
    console.error("Ошибка! Укажите значение true или false.");
   }
  }
 }], [{
  key: 'getDefaultTitle',
  value: function getDefaultTitle() {
   return "Задача";
  }
 }]);

 return Task;
}();

;

Task.count = 0;

var task = new Task("Выучить JavaScript");
console.log(task.done, task._done);
task.complete();
console.log(task.done, task._done);



Здесь очень много сгенерированного кода но в целом, в принципе, можно различить название класса Task свойства и пр.

Если выписали объектно-ориентированный JavaScript используя ES5, то вы писали, скорее всего, что-то похожее на то что сгенерировал Babel. Не совсем конечно, но близко.

Лично я очень рад что в JavaScript наконец-то появились классы.

Но многие программисты могут со мной не согласится, так как JavaScriptэто больше функциональный язык нежели чем классический.

А прелесть JavaScript заключается в том, что если выходите пользоваться классами, то можете пользоваться классами если хотите писать функциональной код Можете писать функциональный код. Здесь каждый найдёт что-то по душе!

Далее рассмотрим наследование.



                                                                                                                                                             

вторник, 18 сентября 2018 г.

Работа с REPL. Основные команды.

REPL - read eval print loop это интерактивный компонент, который поставляется вместе с Node.js




При работе в Node.js часто приходится запускать целые файлы или части кода для тестирования. Для удобства можно использовать REPL, просто набрав в КС (здесь и далее - командная строка):

node


Нажать Enter.

Без ключевого слова var будет возвращать введенные выражения, а с var - undefined



Так происходит потому что в результате операции присваивания значения переменной не возвращает результат.

Вот интересный пример:



Ожидали увидеть true?

Не забывайте, что интерпретатор пойдет слева направо и вначале сравнит 3 и 2. Получит true. И только потом сравнит true и 1 и получит false

3>2==1 будет true, потому что при не строгом сравнении true==1

Можете проверить!

Многострочный и сложный JS код

JS код можно набирать в REPL точно так же как в обычном файле, включая необходимые инструкции для импорта модулей.

Пример с модулем Query String:



Переменная qs без var и нажать Enter. Пока мы работаем без var, то сразу видим результат. В данном случае это интерфейс объекта querystring.

REPL предоставляет возможность введения многострочного кода после любой открывающей скобки { или (. При вложенности, просто увеличивается кол-во точек перед введенным кодом.

Здесь можно также вставлять блоки кода - правая кнопка мыши и выбрать "Вставить".

Основной объект Node.js global на официальном сайте Node.js документирован довольно слабо. Чтобы это испавить, вы можете посмотреть всё информацию об этом объекте просто набрав:

console.log(global);


Или:

gl = global;


Для перехода по уже набранным вами командам, можно воспользоваться стрелками "вверх" - "вниз" - . Выбрать нужную и нажать Enter.

Управление REPL с помощью команд.
  • Ctrl + C - Завершает выполнение текущей команды. Повторное нажатие - выход из REPL.
  • Ctrl + D или написать в консоли .exit - Выход из REPL.
  • Tab - Автоматическое завершение имени глобальной или локальной переменной.
  • - Переход вверх по списку введенных команд.
  • - Переход вниз по списку введенных команд.
  • _ -(нижнее подчеркивание) - ссылка на результат вычисления после выражения.


Ниже приведу список команд для ввода в поле REPL:

  • .break - Если вы запутались с введением многострочного кода, эта команда вернет вас к самому началу, но весь многострочный код будет потерян.
  • .clear - Перезапуск объекта контента и очистка любого многострочного выражения. Эта команда по сути запускает сеанс с самого начала.
  • .exit - Выход из REPL
  • .help - Вывод всех доступных команд.
  • .save - Сохранение текущего REPL сеанса в файле.
  • .load путь/к/файлу.js - Загрузка файла в текущий сеанс (


Команда .save путь/к/файлу/для/сохранения.js сохраняет в файле все, что было введено в текущий объект контента. Пока не будет специально создан новый объект контента или использована команда .clear. Контент включает в себя все, что было введено в текущий REPL сеанс.

Node компонент REPL является удобным интерактивным средством упрощающим разработку. REPL позволяет не только проверять код перед его включением в файлы, но и создавать приложения в интерактивном режиме, сохраняя результаты после завершения.

Еще одним полезным свойством REPL является возможность создания собственной, нестандартной версии. Позволяющей исключить ответы в виде undefined и предварительно загружать модули.

Если вы собираетесь использовать REPL для разработки, то не забывайте чаще сохранять свою работу!



                                                                                                                                                             

вторник, 11 сентября 2018 г.

ES6: Объекты (VIII).

Объекты в ES6

Рассмотрим нововведения, которые помогут нам работе с объектами в ES6.



Все материалы по ES6


В отличии от других языков, в JavaScript мы очень часто работаем с литералами объектов. То есть с простыми объектами, которые не являются представителями какого-либо класса, а представляют из себя набор свойств и значений.

В ES6 было добавленно несколько нововведений, которые немного упростили синтаксис при работе с простыми объектами.

Первое, что мы сделаем, это запустим скрипт Babel, который будет следить за файлами и при их изменении создавать свежие версии.

Откроем папку проекта в командной строке (КС). Вводим команду:

npm run watch


И нажать Enter

Последние версии браузеров поддерживают все новвовведения для объектов без транспиляции. Измененый код нас будет интересовать в порядке ознакомления.

В папке src создадим файл objects.js и сразу укажу его в файле index.html

<script src="src/objects.js"></script>

Начнем со свойств.

Допустим, имеется три переменные - имя, фамилия и электронная почта.


let firstName = "Bill",
    lastName = "Smit",
    email = "bill@gmail.com";



Далее, создадим объект в котором в качестве свойств мы укажем названия переменных:


let firstName = "Bill",
    lastName = "Smit",
    email = "bill@gmail.com";

let person = {
 firstName: firstName,
 lastName: lastName,
 email: email
};

console.log( person );



И в конце мы вывели значения объекта person в консоли браузера.



В ES6, если свойство совпадает с названием переменной, то мы можем указать только свойство. Значение автоматически вставится из переменной с таким же названием.

Объекст person мы можем записать так:


let person = {
 firstName,
 lastName,
 email
};



Сохраняем, и видим тотже результат, что и на фото выше.

Давайте посмотрим на то, что транспилировал Babel

dist/object.js


"use strict";

var firstName = "Bill",
    lastName = "Smit",
    email = "bill@gmail.com";

var person = {
 firstName: firstName,
 lastName: lastName,
 email: email
};

console.log(person);



Он сделал тоже самое, что у нас было изначально!

Теперь перейдем к методам

Создание методов тоже стало немного проще.

Давайте добавим нашему объекту метод.


let firstName = "Bill",
   lastName = "Smit",
   email = "bill@gmail.com";

let person = {
 firstName,
 lastName,
 email,
 say: function() {
  console.log(`Hello, my name is ${firstName} ${lastName}`);
 }
};

console.log( person );
person.say();





В ES6 мы можем немного упростить написание метода, а именно - убрать слово function и двоеточие, оставив только круглые скобки ()


 say() {
  console.log(`Hello, my name is ${firstName} ${lastName}`);
 }


В консоле мы увидим тотже самый результат.

Если посмотреть на транспилированный код, то можно увидеть то, что Babel сделал все ,как и было изначально:

dist/object.js


"use strict";

var firstName = "Bill",
    lastName = "Smit",
    email = "bill@gmail.com";

var person = {
 firstName: firstName,
 lastName: lastName,
 email: email,
 say: function say() {
  console.log("Hello, my name is " + firstName + " " + lastName);
 }
};

console.log(person);
person.say();



Как вы уже знаете, в JavaScript свойства объекта, или метод, можно указать двумя способами: чрез точку, или через квадратные скобки.

Добраться до свойства firstName объекта person мы можем используя точку - person.firstName или квадратные скобки - person['firstName'].

Если мы используем квадратные скобки, то мы можем либо строкой указать название сво-ва, либо название переменной, в которой указано это сво-во.

Создадим новую переменную в которой в качестве значения укажем название свойства.

let property = 'firstName';

Далее в квадратных скобках мы можем указать название переменной

person[property]; Это будет тоже самое, что и person['firstName'];

Теперь, если поменять значение переменной на lastName

let property = 'lastName';

Так мы получим доступ к свойству lastName

Так можно сделать только в том случае если объект уже существует!!!


Но в ES6 мы можем использовать квадратные скобки прями внутри объекта. Тем самым динамически указывать названия сво-ва.

Например:


let property = 'lastName';
person[property]; // person['firstName']
person = {
    [property]: 'Bill'
};


В данном случае person будет присвоен объект, в котором сво-ва мы указываем динамически из переменной property.

Для того, чтобы указать firstName нам нужно указать в параменной let property - 'firstName'.

Вот так:

let property = 'lastName';

и так далее. Мы можем динамически менять значение переменной.

Для более практичного примера я создам функцию createCar, которая будет принимать название свойства - property и значение свойства - value.

В функции мы создадим простой объект с одним свойством и вернем его.

Как мы и говорили, в ES5 после создания объекта можно динамически указать название свойства.

Вначале создаем объект - var car ={}

Далее в квадратных скобках указываем его свойства car[property]

и присваеваем ему значение value

car[property] = value

И возвращаем объект - return car

Чтобы посмотреть на результат console.log(createCar('vin', 1));


function createCar( property, value ) {
 var car = {};
 car[property] = value;
 return car;
};

console.log(createCar('vin', 1));





В консоле мы увидим объект со свойством vin и значением - 1.

В ES6 мы можем указать значение свойства прямо в литерале объекта.

Поэтому мы сразу вернем объект - return

и в свойствахв квадратных скобках мы указываем переменную [property] со значением value.

[property]:value


function createCar( property, value ) {
 return{
  [property]: value
  };
};
console.log(createCar('vin', 1));



В консоле мы получим тотже самый результат.

И теперь давайте посмотри как это все сгенерировал Babel

dist/object.js

function _defineProperty(obj, key, value) { 
if (key in obj){ 
Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });
 } 
else { 
obj[key] = value; } return obj;
 }

function createCar(property, value) {
 return _defineProperty({}, property, value);
};
console.log(createCar('vin', 1));



Функция _defineProperty обращается к глобальному объекту, чтобы создать свойства.

Благодаря новому синтаксису нам нет в этом необходимости и записи стали проще.

И, так как мы используем название переменной, у нас появились новые возможности, которых не было раньше при создании объекта.

Мы можем теперь добавить нижнее подчеркивание к названию совойства ['_' + property]: value


function createCar( property, value ) {
 return{
  [property]: value,
  ['_' + property]: value
  };
};
console.log(createCar('vin', 1));



У объекта появилось новое свойство - _vin



Или мы можем использовать метод toUpperCase()


function createCar( property, value ) {
 return{
  [property]: value,
  ['_' + property]: value,
  [property.toUpperCase()]: value
  };
};
console.log(createCar('vin', 1));



Результат - новое свойство VIN:



Можно динамически указать название метода:

function createCar( property, value ) {
 return{
  [property]: value,
  ['_' + property]: value,
  [property.toUpperCase()]: value,
  ['get' + property]() {
       return this[property];
      }
  };
};
console.log(createCar('vin', 1));



Теперь у обекта появился динамически заданный метод getvin



В JavaScript помимо свойств и методов, можно создавать специальные свойства, которые внутри объектов выглядят и работают как методы, но снаружи работаеют как свойства.

Эти суппер-свойства называются get и set или геттер и сеттер.

Давайте вернемся к объекту person и добавим ему оба этих метода.

Вначале добавим их в стиле ES5:

Чтобы добаить свойство мы воспользуемся объектом Objcts методом .defineProperty()

Первым параметром будет объект которому создаются свойства - person, а вторым параметром название свойства 'fullName', а далее принимается объект в котором это свойство описаывается.

В этом объестк первым свойством будет get - функция, которая ничего не принимает, но возвращает (this.firstName + ' ' + this.lastName).

Перед тем, как посмотреть результат я закоментирую код, который не относится к объекту person


Object.defineProperty(person, 'fullName', {
    get: function() {
        return this.firstName + ' ' + this.lastName;
    }

});



Сохраняем. Смотрим в консоле.

Теперь у нашего объекта person появилось новое свойство - fullName (на фото ниже оно подчеркнуто.

Теперь если мы обратимся к нему через точечную нотацию в консоле - person.fullName , то получим "Bill Smit", как на фото ниже в рамке.



Обратите внимание что get является функцие, но при этом мы не используем круглые скобки.

Внутри объекта - это метод, а снаружи это свойства!

Особого смысла метод set, в данном случае, не имеет, но для полноты картины, мы его определим. Его отличие от get в том. что set получает значение. Его можно назвать как угодно - это просто переменная. В нашем случае - value. В теле метода мы можем что-либо сделать - напрмер присвоить свойство this.firstName = value;


let person = {
    firstName,
    lastName,
    email,
    sayHello() {
        console.log(`Hi my name is ${this.firstName} ${this.lastName}`);
    },
    get fullName() {
        return this.firstName + ' ' + this.lastName;
    },
    set fullName(value) {
        this.firstName = value;
    }
};



Сохраним и посмотрим в консоле:



  1. - мы увидим, что у нашего объекта появились два метода (геттер и сеттер).
  2. - назначим новое значение свойству fillName - > person.fullName = "John";
  3. - вывдеме значение этого свойства - person.fullName


Для того, чтобы переписать код на ES6, все что нам нужно сделать это добавить к нашему объекту person


let person = {
    firstName,
    lastName,
    email,
    sayHello() {
        console.log(`Hi my name is ${this.firstName} ${this.lastName}`);
    },
    get fullName() {
        return this.firstName + ' ' + this.lastName;
    },
    set fullName(value) {
        this.firstName = value;
    }
};



Результат в консоли будет тот же.



Чаще всего свойства get и set не присваиваются простым объектам. Они присваиваются, как правило, объектам - представителям какого-нибудь класса.

В ES6 добавили поддержку классов. О них мы поговорим позже.



                                                                                                                                                             

понедельник, 10 сентября 2018 г.

ES6: Цикл for...of (VII).

Цикл for...of

Сегодня мы рассмотрим цикл for...of, благодаря которому мы можем итерировать массивы и другие структуры.



Все материалы по ES6


Первое, что мы сделаем это запустим скрипт Babel, который будет следить за файлами и при их изменении создавать свежие версии.

Откроем папку проекта в командной строке (КС). Вводим команду:

npm run watch


И нажать Enter

Последние версии браузеров поддержвают параметры по умолчанию без транспиляции. Изменнеый код нас будет интересовать в порядке ознакомления.

В папке src создадим файл for.js и сразу укажу его в файле index.html

<script src="src/for.js"></script>

Последние версии браузеров поддерживают цикл for...of без транспиляции.

Цикл for...of очень похож на цикл for...in.

Разница в том, что for...of перебирает значения, в то время как for...in - ключи.

Если вы забыли как работает цикл for...in, то можно посмотреть это на примере:

Создадим массив с некоторыми значениями и попробуем вывести значения в консоль, используя цикл for...in и выведем сам массив.


let animals = ['cat', 'dog', 'hamster', 'fish', 'goat'];
for( animal in animals ) {
 console.log(animal);
};
console.log(animals);



В консоли мы увидим:



Вывели циклом for...in ключи массива, а нам нужно значения.

Конечно, имея ключ мы можем сделать так:


let animals = ['cat', 'dog', 'hamster', 'fish', 'goat'];
for( let animal in animals ) {
 console.log(animal);
};

for( let index in animals ) {
 console.log( animals[index]);
};

console.log(animals);





Мы так же можем воcпользоваться методом for...of


let animals = ['cat', 'dog', 'hamster', 'fish', 'goat'];
for( let animal in animals ) {
 console.log(animal);
};

for( let index in animals ) {
 console.log( animals[index]);
}

for( let animal of animals ) {
 console.log( animal );
}

console.log(animals);





Таким образом мы сможем легко вывоить значения циклом без использования кллючей.

Давайте посмотрим на то, что сгенерировал Babel


'use strict';

var animals = ['cat', 'dog', 'hamster', 'fish', 'goat'];
for (var animal in animals) {
 console.log(animal);
};

for (var index in animals) {
 console.log(animals[index]);
}

var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;

try {
 for (var _iterator = animals[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
  var _animal = _step.value;

  console.log(_animal);
 }
} catch (err) {
 _didIteratorError = true;
 _iteratorError = err;
} finally {
 try {
  if (!_iteratorNormalCompletion && _iterator.return) {
   _iterator.return();
  }
 } finally {
  if (_didIteratorError) {
   throw _iteratorError;
  }
 }
}

console.log(animals);



Если честно, то совсем нет желания разбираться с тем, что там происходит. :-)

Меня вполне устраивает цикл for...of!

Помимо массивов цикл for...of позволет итеррировать и новые структуры, которые будут добавлены в ES6 - это объекты set и map.

О них чуть позже.



                                                                                                                                                             

воскресенье, 9 сентября 2018 г.

ES6: Параметры функции (VI).

Параметры функции





Все материалы по ES6


В JavaScript работа с параметрами функции очень гибкая. Например: Ничто не помешает отправить в функцию больше, или меньше аргументов, чем нужно. Но "Большая сила несет за собой большую ответсвенность!"

И в больших приложениях на JavaScript такая гибкость может создать проблемы. В ES6 есть два нововведения, касающихся параметров функции, которые могут сделать работу с ними более удобной и понятной.

  • Параметры по умолчанию (default parameters).
  • Оставшиеся параметры (rest parameters).

Параметры по умолчанию (default parameters).

Первое что мы сделаем это запустим скрипт Babel, который будет следить за файлами и при их изменении создавать свежие версии.

Откроем папку проекта в командной строке (КС). Вводим команду:

npm run watch


И нажать Enter

Последние версии браузеров поддержвают параметры по умолчанию без транспиляции. Изменнеый код нас будет интересовать в порядке ознакомления.

В папке src создадим файл parameters.js и сразу укажу его в файле index.html

<script src="src/parameters.js"></script>

Лучше всего понять это на примере:

Создадим функцию greet(), которая будет принимать два параметра greeting, name, а в консоле выводить сообщение приветствия.

console.log(`${greeting} ${name}`);

Здесь мы воспользовались шаблонной строкой.

Теперь можно вызвать функцию со следующими аргументами:

greet("Hi", "Bill"); parameters.js


function greet(greeting, name) {
 console.log(`${greeting} ${name}`);
};
greet("Hi", "Bill");



Результат будет вывод в консоль сообщения Hi Bill, как на фото ниже.



Теперь попробуем опустить один из парамеров.

greet("Hi");

В консоле мы увидим Hi undefined.



Так произошло, потому что мы не отправили параметр и ему присвоено значение undefined.

Мы можем отправить значение undefined сами.

greet(undefined, "Bill");

Результат:



И как можно предположить, если вызвать эту функцию вообще без аргументов, то в консоле получим undefined undefined.

Для того, чтобы функция работала правильно, нам следует проверить значения параметров перед тем, как мы ее используем.

Это можно сделать несколькими способами. Для того, чтобы лучше понять - воспользуемся самым объемным и запутанным. :-)


function greet(greeting, name) {
    if (greeting !== undefined && name !== undefined) {
        console.log(`${greeting} ${name}`);
    } else if (greeting === undefined && name !== undefined) {
        console.log(`Hello ${name}`);
    } else if (greeting !== undefined && name === undefined) {
        console.log(`${greeting} friend`);
    } else {
        console.log('Hello friend');
    }
}



Я думаю, что здесь все понятно, не смотря на относительно большой блок кода. Здесь идет обычная проверка переданных в функцию аргументов в блоках if, и если один из параметров undefined, то тогда ему назначаем новый параметр.

Запустим, чтобы убедиться и увидим в консоле:



Это значит, что функция работает правильно!

Но данный алгоритм ужастен и так писать код в JavaScript ненужно!

Очень много кода ушло только на то, чтобы проверить значения двух параметров.

А если их много? Пять! Десять!

Мы можем намного упростить код используя параметры по умолчанию!

Это можно сделать очень просто!


function greet(greeting = "Hello", name = "friend") {
 console.log(`${greeting} ${name}`);
};

greet("Hi", "Bill");
greet("Hi");
greet(undefined, "Bill");



В результате мы увидим в консоле:



Теперь можно посотреть на транспилированный код - dist/parameters.js


"use strict";

// function greet(greeting, name) {
//  console.log(`${greeting} ${name}`);
// };
// greet("Hi", "Bill");
// greet("Hi");
// greet(undefined, "Bill");


// function greet(greeting, name) {
//     if (greeting !== undefined && name !== undefined) {
//         console.log(`${greeting} ${name}`);
//     } else if (greeting === undefined && name !== undefined) {
//         console.log(`Hello ${name}`);
//     } else if (greeting !== undefined && name === undefined) {
//         console.log(`${greeting} friend`);
//     } else {
//         console.log('Hello friend');
//     }
// }

function greet() {
 var greeting = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "Hello";
 var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "friend";

 console.log(greeting + " " + name);
};

greet("Hi", "Bill");
greet("Hi");
greet(undefined, "Bill");



Babel сделал то, что мы сделали бы и сами. Использовал переменные, оператор "или" - || и тернарный оператор - ?.

Теперь перейдем к оставшимся параметрам.



Оставшиеся параметры (rest parameters)

Предположим, что требуется написать функцию, которая складывает числа. Заранее мы не знаем сколько будет параметров. Поэтому вызов функции может выглядт следующим образом:

sum(5, 7, 2, 10);

Теперь напишем саму функцию. Но, что нам делать с параметрами, если мы не знаем сколько их будет?

До ES6 мы использовали объект arguments. Данный объект не указывается в списке параметров и доступен в любой функции.


function sum(){
 console.log(arguments);
};
sum(5, 7, 2, 10);



Давайте посмотрим на этот объект в консоле.



С первого взгляда может показаться, что это массив, но это не так.

Это объект названия свойств которого представляют числа.

В этом можно убедиться используя оператор instanceof


function sum(){
 console.log(arguments instanceof Array);
};
sum(5, 7, 2, 10);



В консоле мы увидим false - подтверждение того, что arguments не является массивом.

Для того, чтобы итерировать arguments мы мжем использовать цикл for, но мне кажется, что намного проще использовать метод forEach, который доступен всем массивам. Пробелам лишь в том, что arguments не массив. У него нет этого метода.

Мы можем сделать следующее:

Используя проттип объекта Array - Array.prototype мы можем использовать метод call() метода forEach forEach.call(). Туда передадим объект arguments и функцию обратного вызова, которая примет параметры value (index и array но они нам не нужны).

Нам потребуется переменная. И так как мы пишем в ES5, то мы объявим ее через var.


function sum(){
 console.log(arguments instanceof Array);

 var sum = 0;
 Array.prototype.forEach.call(arguments, function(value){
  sum += value;
 });
 console.log(sum);
};
sum(5, 7, 2, 10); //24


Эта функция выведет в консоль 24.

В ES6 в таком написании нет необходимости, но знать, как работает эта функция нужно!

Если мы пишем код на ES6, то мы можем воспользоваться оставшимися параметрами.

Синтаксис очень простой и выглядит следующим образом.


function sum(...values){
    console.log(values);
}


Очень похоже на оператор разворота, но работает по другому.

Если оператор разворота разворачивает массив и представляет аргументы по отдельности, то синтаксис оставшихся параметров наоборот - превращает отдельные элементы в массив.

Таким образом values будет полноценным массивом.

Мы можем посмотреть на него в консоле и увидет значения массива.



Для того, чтобы убедиться в том, что это массив, мы можем воспользоваться оператором instanceof

function sum(...values){
 console.log(values instanceof Array); //true
}



В коносле мы увидим true.

Тепер мы перепишем нашу функцию используя ES6.

Так как это массив мы можем использовать метод forEach сразу на values.


function sum(...values){
 console.log(values instanceof Array);
 let sum = 0;
 values.forEach(function(value){
  sum += value;
 });
 console.log(sum); //24
}



В консоль выведет снова - 24!

Мы можем еще больше упростить функцию, воспользовавшись методом - reduce, который есть у всех массивов. Данный метод можно использовать, чтобы сложить элементы массива.

Функция обратного вызова в качестве первого параметра принимает предыдущее значение - prevValue, currentValue


function sum(...values) {
    console.log(values.reduce(function(prevValue, currentValue) {
        return prevValue + currentValue;
    }));
}


sum(5, 7, 2, 10);



Данный код выведет -24.

Шпаргалка по ES6





                                                                                                                                                             

суббота, 8 сентября 2018 г.

ES6 Template Strings. Шаблонные строки (V).

Template Strings. Шаблоны или шаблонные строки.





Все материалы по ES6


Еще одним приятным добавлением в ES6 являются шаблоны или шаблонные строки (template literals or template strings).

Они представлюят функционал очень похожий на шаблонизаторы.

Первое что мы сделаем это запустим скрипт Babel, который будет следить за файлами и при их изменении создавать свежие версии.

Откроем папку проекта в командной строке (КС). Вводим команду:

npm run watch


И нажать Enter

Последние версии браузеров поддерживают шаблоны без транспиляции. Измененный код нас будет интересовать в порядке ознакомления.

В папке src создадим файл templates.js и сразу укажу его в файле index.html

<script src="src/templates.js"></script>

Сначала в примере я воспользуюсь простой строкой, а потом заменю её на шаблонную.

В этом файле мы создадим функцию greet(name), которая будет принимать имя.

Функция выведет сообщение "Hello " + name в консоле браузера.


function greet( name ) {
 console.log("Hello " + name );
};

greet("Bill");



В консоле мы увидим:



Теперь давайте изменим простую строку на шаблонную.

Для этого нам нужно заменить обычные кавычки на обратные.

Клавиша обратных кавычек ` находится на клавиатуре в верхнем левом углу - буква Ё в русской раскладке.

Поместим весь наш "вывод" в обратные кавычки, удалим плюс оставим пробел и поместим нашу переменную в фигурные скобки -{}, поставив перед ними знак доллора ${имя_переменной}.

Сочетание ${} еще называется местозаполнителем


function greet( name ) {
 console.log(`Hello ${name}` );
};

greet("Bill");



Если посмотреть на резулльтат в браузере, то он будет таким же, но при этом использовать шаблон куда легче. Главное - не забывать ставить пробелы и переносы строк, которые автоматически будут отображаться при выводе в консоль.

Если посмотреть на тип шаблонной строки используя оператор typeof:

console.log(typeof`Hello ${name}` ); // string

Это значит, что шаблоны такие же строки! То есть - мы можем с нми использовать все методы строк!

Например: Мы можем вывести сообщение так, чтбы все буквы были заглавными.


function greet( name ) {
 console.log(`Hello ${name}`.toUpperCase() );
};

greet("Bill");





Теперь давайте посмотрим на то, что создал Babel dist/templates.js


"use strict";

function greet(name) {
 console.log(("Hello " + name).toUpperCase());
};

greet("Bill");



Он сделал то, что мы с вами и сами бы написали, если бы использовали обычную строку.

Многострочность.

Шаблонные строки, также поддерживают многострочность. То есть их можно спокойно переносить на несколько строк.

Посмотрим на примере.

Мы создадим новую функцию, которая будет принимать параметры - откого, кому, тема и сообщение.

И вызовем эту функцию с некторыми аргументами:


function createEmail( to, from, subject, message ) {
 console.log(`
   to: ${to}
   from: ${from}
   subject: ${subject}
   message: ${message}
  `);
};

createEmail("john@mail.com", "elen@mail.com", "Hello", "How are you?");





Как вы можете убедиться, вывод в консоле состоялся именно так, как мы и написали - в 4 строки и с соблюдением табуляции.

Теперь посмотрим на то, как это сгенерировал Babel -> dist/templates.js


function createEmail(to, from, subject, message) {
 console.log("\n\t\t\tto: " + to + "\n\t\t\tfrom: " + from + "\n\t\t\tsubject: " + subject + "\n\t\t\tmessage: " + message + "\n\t\t");
};

createEmail("john@mail.com", "elen@mail.com", "Hello", "How are you?");



Создадим функцию, которая будет скалдывать два числа и выводить в консоль в виде арифметического примера.

Вызовем функцию с призвольными числами:


function add( x, y ) {
 console.log(`${x} + ${y} = ${x + y}`)
}

add( 4, 7 );



Здесь первый +, является частью строки. Второй + является частью выражения и складывает наши переменные.

В результате мы увидм:



А что если мы полчаем данные от пользователя со страницы?

Данные будут в виде строк.

Вызовем функцию так add( '4', '7' );

Резуьтат:



так получилось, потому что мы складывали строки.

Для того, чтобы убедиться. что мы складываем именно числа, мы можем применить функцию parseInt()


function add( x, y ) {
 console.log(`${x} + ${y} = ${parseInt(x) + parseInt(y)}`)
}

add( '4', '7' );



В результаье будет 11, как и в предыдущем примере.

То ест - сложение будет правильным.

Тегирование

Пожалуй, самой интересной особенностью шабблонных строг является тегирование, благодаря которому мы можем изменить вывод шаблонов при помощи функции.

Посмотрим на примере:

Простой вывод в консоль имени (переменной).


let name = "Bill";

console.log(`Hello ${name}`);



Результат:



А теперь я хочу, чтоб name всегда выводилась большими буквами.

Для этого я могу присвоить шаблону тег. Тегом будет название функции, которой я смогу обработать строку.

Для начала я создам функцию и назову её upperName(), первый аргумент которой будет содержать массив строковых литералов literals.

Второй и последующие аргументы содержат значения вычесленных выражений. Мы отправлем одно - name. Но если бы мы отправляли несколько, то

value1, value2, value3 и т.д.


function upperName(literals, value) {
 console.log(literals, value);
}



В том случае, когда мы не знаем сколько их будет, то в ES6 есть синтаксис оставшиеся параметры функции. Он предоставляет неогрмниченное множество аргументов в виде массива. Мы можем поставить три точки перед ...values. Теперь ...values будет массивом аргументов.

Пример:


function upperName(literals, ...values) {
 console.log(literals, value);
}



Для того, чтобы присвоить шаблону тег, я просто напишу название функции перед ним


let name = "Bill";

console.log(upperName`Hello ${name}`);

function upperName(literals, value) {
 console.log(literals, value)
}


Посмотрим в консоль:



В консоле мы увидим массив, в котором содержатся строки из которых состоит шаблон и значение переменной name.

Функция должна возвращать строку, но до этого мы можем сделать с ней все что угодно.

Как я и хтел я сделаю так, чтобы имя отображалось заглавными буквами.


let name = "Bill";

console.log(upperName`Hello ${name}`);

function upperName(literals, value) {
 return literals[0] + value.toUpperCase();
}



То есть, мы взяли первый литерал - Hello и прибавили к нему значение value, в кторм сделали все буквы заглавными - .toUpperCase().



Так мы сделали все буквы в переменной name заглавными.

В JavaScript, который работает нпрямую с HTML-шаблоном, шаблонные строки открывают массу дополнительных возможностей!



                                                                                                                                                             


Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.Пишите мне - kolesnikovy70 почта gmail.com