Translate

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

вторник, 2 октября 2018 г.

Основы Node JS & Express ( III ).

Основы Node JS & Express ( III ).

Разбираемся, что такое npm и для чего он нужен. Устанавливаем Express и шаблонизатор EJS. Делаем полную подготовительную работу и начинаем создавать свой собственный сайт на NodeJS.



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


Пакетный менеджер npm.

npm - это менеджер пакетов для JavaScript и крупнейший в мире реестр программного обеспечения.

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

npm полностью бесплатный и скачивается вместе с установкой Node.JS.

Установить нужные пакеты или библиотеку очень просто. В поиск на сайте npm вводите название нужной библиотеки и получаете полное руководство по установке.

Для установки нужно в КС (командной строке) перейти в папку проекта и набрать:

npm install package_name


package_name - название пакета, или библиотеки.

Удалить:
npm uninstall package_name


Нажать Enter.

Файл package.json.

Когда вы работаете над проектом и захотите отправить свой код какому-либо другому программисту, то вам не нужно будет отправлять все библиотеки и модули, которые у вас есть в проекте. Это очень затратный процесс. Вы сможете отправить свой код без библиотек. В файле package.json будет вся информация по вашему проекту и зависимостях и любой разработчик сможет легко развернуть ваш проект на любой машине используя ту информацию, которая есть в файле package.json. Ему будет достаточно просто прописать в КС команду

npm install


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

Создание файла package.json

Для создания этого файла можно просто ввести в КС:

npm init


Далее можно заполнить предложенные строки, или просто нажимать Enter. В конце согласиться - нажать y и Enter.

После этого в папке проекта появится новый файл - package.json. Если его открыть, то вы увидите там все информацию по проекту.

Раздел dependencies служит для сохранения всех зависимостей нашего проекта.

Экспресс

Библиотека Express хороша по многим причинам. Она позволяет значительно упростить написание кода. Например: отслеживание url-адресов здесь будет настроено намного проще, нежели в NodeJS. Кроме того здесь есть различные шаблонизаторы, которые позволяют легко выводить html вместе с данными полученными от NodeJS.

Установка Express

Очень простая. Открываем папку нашего проекта в КС. Для этого достаточно просто перетащить туда папку, чтобы получить путь (фишка для windows).

npm install express -save


Флаг -save позволит сразу прописать эту библиотеку в зависимостях dependencies файла package.json.

Работа

чтобы обратиться к библиотеке мы создадим переменную и пропишем:

let express = require('express');

Теперь этот модуль вернет нам функцию, которую мы должны вызвать.

Создадим новую переменную app и обратившись к переменной express вызываем ее, как функцию.

let app = express();

Таким образом мы в переменной app получим доступ ко всем функциям, которые ест ьу нас в библиотеке Express - мы сможем подключиться к серверу, обрабатывать различные ссылки и пр.

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

app.listen(8080);

Маршрутизация в Express

Для отслеживания ссылок:

app.get() - отслеживает get запросы.

app.post()-отслеживает post запросы.

Так, как мы собираемся отслеживать get-запрос на нашу главную страницу. то пишем так:

app.get('/', fn)

fn - вторым параметром - функция, которая похоже на функцию, которая была в NodeJS ранее. У этой функции в Express больше возможностей.

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

res.send('This is Home');

.send() - в Express почти тоже самое, что .end() NodeJS.

index.js


let express = require('express');

let app = express();

app.get('', function(req, res){
	res.send('This is Home');
});

app.listen(8080);



В КС

node index.js




Вывели текст на страницу. Если попробовать перейти на др страницу, например http://localhost:8080/test,

то увидим:



Если бы мы прописали еще один обработчик:


let express = require('express');

let app = express();

app.get('/', function(req, res){
	res.send('This is Home');
});
app.get('/news', function(req, res){
	res.send('This is News');
});
app.listen(8080);





Выводить html текст здесь так же просто.

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

То есть эти ссылки никак не меняются.

А что если нам нужно отследить ссылку с каким то ID статьи? Например /news/23

Для этого нам нужно добавить еще один /: и абсолютно любое имя, которое мы захотим.

Например так:


app.get('/news/:id', function(req, res){
	res.send('This is News');
});



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

req.params.id - здесь id - название отслеживаемого параметра. Оно будет любое, но точно такое как и /news/:id



В данном случае, id может быть строкой, числом и вообще всем чем угодно :-) Это не привязывает нас к числам!

Можно поменять id на name или любое другое.


app.get('/news/:name', function(req, res){
	res.send('ID is - ' + req.params.name);
});



По этому id мы можем брать информацию из базы данных и показывать (статью. фото и пр).

Отслеживать несколько параметров:


app.get('/news/:name/:id', function(req, res){
	res.send('ID is - ' + req.params.name + req.params.id);
});





Использование шаблонизатора.

Отображаем html-файлы в браузере

До этого мы использовали метод send(), теперь нам нужно использовать метод - sendFile(), которому мы должны передать путь к файлу.


let express = require('express');

let app = express();

app.get('/', function(req, res){
	res.sendFile(__dirname + '/index.html');
});
app.get('/about', function(req, res){
	res.sendFile(__dirname + '/view/about.html');
});
app.get('/news/:name/:id', function(req, res){
	res.send('ID is - ' + req.params.name + req.params.id);
});
app.listen(8080);



Файлы можно поместить в отдельную папку ( на примере about).

Файлы я взял из части второй этого курса. Если вы не знакомы с ней, то вот ссылка Основы NodeJS - Вторая часть.

Теперь с параметрами, которые постоянно будут меняться.

Если нам нужно создать ссылку на некое значение, после /mews/значение. Оно будет меняться. Например: 23, part или любое др значение.


app.get('/news/:id', function(req, res){
	res.send('ID is - ' + req.params.id);
});



В зависимости от этого параметра мы можем брать данные из БД (базы данных) и выводить конкретную статью.

Нам нужен некий html файл куда мы будем передавать данные нашего id и в зависимости от этих данных выводить ту или иную информацию.

Нам нужен некий шаблонизатор.

Благодаря Express мы можем использовать несколько шаблонизаторов.

Один из них это EJS

Поскольку EJS является дополнительным пакетом, то нам нужно его установить.

npm install ejs


Нажать Enter

После этого он установится в наш проект.

Он позволяет передавать данные в различные шаблоны, причем эти шаблоны будут иметь расширение .ejs.

В этих шаблонах мы сможем выводить наш html код вместе с вставленным в него js кодом (переменными, выводить циклы и многое другое).

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

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

view engine - по сути шаблонизатор.

Поскольку их существует огромное количество, а мы выбрали именно EJS, то мы должны его указать в нашем index.js файле.

Сразу после инициализации переменной app.

app.set('view-engine', 'ejs');

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

На том же уровне, где index.js создадим папку views.

В ней создадим новый файл news.ejs. Это будет некий шаблон, который мы будем наполнять.

В эти шаблоны мы можем помещать самый обычный html-код.

Мы в него добавили обычный html-код:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="wight=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Новости</title>
	<style>
		body {background-color:#98bfd5;}
		.block {text-align: center; width: 70%; margin-left: 15%}
		h1 {color:#494949; font-size: 3.5em}
		p {color:#494949; font-size: 1.2em;}
	</style>
</head>
<body>
	<div class="block">
		<h1>Новостная страница.</h1>
			<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eaque numquam libero, veniam ipsum similique odit molestiae esse quia blanditiis magni debitis aliquam, pariatur nam quaerat quas nemo, facilis temporibus laboriosam.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maiores enim vitae dolore nemo quas aliquam quia corrupti rerum ipsam ad nesciunt, architecto, pariatur officiis. Maxime iste ullam quibusdam, nobis voluptas!</p>
	</div>
</body>
</html>



Идем к файлу index.js. Здесь по ссылке /news/:id я хочу выводить наш шаблон.

Для этого мне не нужно использовать метод .send или .sendFile, а мне потребуется метод render().

Метод render() берет нужный файл (шаблон) в папке views и может отобразить его в браузере. Плюс в этот шаблон он может передать некие параметры.

Расширение в методе render() можно не указывать. Далее можно передать некие параметры в сам шаблон. Поэтому мы передаем вторым параметром - объект. В нем может быть большое количество свойств и значений.

Допустим, что мы решили передать некий параметр newsId со значением req.params.id - то есть значение будет как раз сам вызываемый id.


app.get('/news/:id', function(req, res){
	render('news', {newsId: req.params.id});
});



Таким образом в шаблон news будет передано значение, которое будет называться newsId со значением id.

В файл news.ejs мы можем все это принять и отобразить.

Немного изменим наш файл news.ejs. В заголовок страницы будем выводить ID.

Все можно посмотреть в документации к шаблонизатору EJS (ссылка выше).

Ставим <%= и далее имя свойства, значение которого мы хотим увидеть на странице. Закрыть тег - %>

<h1>Новостная страница c ID = <%= newsId %></h1>

Файл /views/news.ejs


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="wight=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Новости</title>
	<style>
		body {background-color:#98bfd5;}
		.block {text-align: center; width: 70%; margin-left: 15%}
		h1 {color:#494949; font-size: 3.5em}
		p {color:#494949; font-size: 1.2em;}
	</style>
</head>
<body>
	<div class="block">
		<h1>Новостная страница c ID = <%= newsId %></h1>
			<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eaque numquam libero, veniam ipsum similique odit molestiae esse quia blanditiis magni debitis aliquam, pariatur nam quaerat quas nemo, facilis temporibus laboriosam.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maiores enim vitae dolore nemo quas aliquam quia corrupti rerum ipsam ad nesciunt, architecto, pariatur officiis. Maxime iste ullam quibusdam, nobis voluptas!</p>
	</div>
</body>
</html>



Файл index.js


let express = require('express');

let app = express();

app.set('view engine', 'ejs');

app.get('/', function(req, res){
	res.sendFile(__dirname + '/index.html');
});
app.get('/about', function(req, res){
	res.sendFile(__dirname + '/about.html');
});
app.get('/news/:id', function(req, res){
	res.render('news', {newsId: req.params.id});
});
app.listen(8080);





Мы можем передавать несколько параметров. Например:


app.get('/news/:id', function(req, res){
	res.render('news', {newsId: req.params.id, newParam: 535});
});



, а в файле news.ejs выведем его на страницу, например так:

<p><%= newParam %></p>

Помимо этого мы можем передавать и собственные объекты. Например, создадим объект:


app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4};
	res.render('news', {newsId: req.params.id, newParam: 535});
});



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

Например:


app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4};
	res.render('news', {newsId: req.params.id, newParam: 535, obj: obj});
});




	<p><b>Title = </b><%= obj.title %></p>
	<p><b>ID = </b><%= obj.id %></p>
	<p><%= newParam %></p>





Передача в шаблон массива.

Создадим массив данных и выведем его с помощью цикла.


app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4, paragraphs:['Параграф', 'Обычный текст', 'Числа: 3, 7, 24', 476]};
	res.render('news', {newsId: req.params.id, newParam: 535, obj: obj});
});



Все, что мы добавили будет передано в шаблон, так как объект obj уже будет передан в шаблон.

Теперь в самом шаблоне мы просто выведем этот массив циклом:


			<ul>
				<% obj.paragraphs.forEach(function(item) { %>
				<li><%= item %></li>
			<% }); %>
			</ul>





Статические файлы и промежуточное ПО.

Файлы, которые можно включить в другие файлы.

Сейчас у нас есть один шаблон - news.ejs, а представьте. что их много. Десятки. И вам потребуется внести изменения в какую-то часть кода, который встречается во всех этих файлах. Придется вносить множество изменений.

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

В папке шаблонов views создадим папку blocks , а в ней файл hrader.ejs.

Файл hrader.ejs


<ul>
	<li><a href="/">На главную</a></li>
	<li><a href="/about">Про нас</a></li>
	<li><a href="/news/новости">Новости</a></li>
</ul>



Теперь нам нужно этот файл подключить во всех шаблонах. Идем в файл news и сразу после открывающего тега body записываем:

<% include blocks/header.ejs %>

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



Статические файлы.

Создадим новую папку на уровне index.js с названием public. В ней будут находиться все статические файлы. Это css-файлы, картинки, документы и пр. Все те файлы. которые будут вызываться с различных страниц нашего сайта.

В этой папке создадим еще одну папку - css и уже в ней создадим файл style.css.

В него перенесем весь код стилей из файла index.ejs

В файлах .ejs подключаем стили:

<link rel="stylesheet" type="text/css" href="/public/css/style.css">

Если теперь проверить, то ничего не произойдет. Стили не подключатся.

Для подключения статических файлов нам нужно использовать промежуточное программное обеспечение:

В файле index.js вверху, сразу за app.set, мы должны написать:

app.use('/public', );

И теперь, если мы где то будем использовать ссылку начинающуюся с /public сам NodeJS и Express будет понимать, что мы используем статические файлы и будет подключать все верно.

вторым - где мы их ищем express.static('public') т. есть в папке /public.

Если обобщить, то в коде app.use('/public', express.static('public')); мы отслеживаем ту ссылку, которую прописываем в

<link rel="stylesheet" type="text/css" href="/public/css/style.css">

Если бы у на было бы вот так:

<link rel="stylesheet" type="text/css" href="/assets/css/style.css">

то и в этом коде было бы:

app.use('/assets', express.static('public'));

В данном случае public указывает на папку!

Если так и оставить, то никаких изменений не произойдет. Файл подключится, потому что мы будем отслеживать ссылку assets .

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


app.use('/assets', express.static('public'));



Для того, чтобы не путаться, обычно, делают ссылку и папку одного имени. Чаще всего это именно public.

Промежуточное ПО - это то, что мы делаем до того пока отправим какие-то данные на страницу (сервер).

В данном случае это и есть наше промежуточное ПО.

Создание HTML-формы и получение данных

Первое, что мы сделаем это добавим саму форму на наш сайт.

Открываем файл about.ejs и сюда мы будем добавлять форму используя технологию bootstrap.

Идем на сайт Bootstrap.

Нажимаем на Get Started, копируем css ссылку для подключения и вставляем ее в head файла about.ejs.

В окно поиска вводим Forms и на найденной странице копируем первую форму сверху.

Сохраним и запустим.



POST -запрос.

Так так мы будем выполнять POST -запрос, то нам необходимо добавить в форму несколько атрибутов.

method="post" - т.к POST -запрос

И action="" - это то куда нужно перенаправить пользователя после того,как он нажмет "Отправить". В нашем случае это:

<form method="post" action="/about">

Все остальное нам нужно сделать в файле index.js

Первым делом нам необходимо скачать пакет, который называется body-parser.

Он нам позволяет брать POST -запрос, который идет от формы и обрабатывать его. Проще говоря - получать все данные из формы.

Для установки, в папке проекта в КС пишем.

npm install body-parser


Нажимаем - Enter.

Пакет устанавливается.



После установки стоит следовать простой инструкции.

Перейдем на сайте в раздел Examples и найдем там раздел Express route-specific

  1. Подключаем нужные для нас модули.


  2. var bodyParser = require('body-parser')

    и

    var urlencodedParser = bodyParser.urlencoded({ extended: false })

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

  3. Далее, на основе документации, мы видим, что нам нужно отслеживать именно POST -запрос и передавать в него некое промежуточное ПО (urlencodedParser). Ранее мы уже отслеживали GET- запросы.


Данные полученные из формы мы выведем в консоль.

console.log(req.body);

Можно сразу добавить проверку. Если не передано никаких данных из формы, мы выдадим просто ошибку.

if (!req.body) return res.sendStatus(400)

В самой форму нужно указать для полей атрибут name. Это будут названия свойств, а значение - это то, что введет пользователь.

about.ejs


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>О нас.</title>
	<link href="https://fonts.googleapis.com/css?family=Poppins" rel="stylesheet">
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
	<link rel="stylesheet" type="text/css" href="/public/css/style.css">

</head>
<body>
	<% include blocks/header.ejs %>
	<div class="container">
		<h1>Hello, It is my first page on Node.js</h1>
		<h2>Заголовок второго уровня.</h2>
		<img src="http://www.chertpz.ru/assets/images/fotogallery_new/phormy_trub/Kvadrat.JPG" alt="">
		<a href="index">На главную</a>
		
		<p>Равным образом укрепление и развитие структуры способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям. Равным образом начало повседневной работы по формированию позиции требуют от нас анализа существенных финансовых и административных условий.</p>
		<h3>третьего уровня заглавие.</h3>
		<p>Значимость этих проблем настолько очевидна, что консультация с широким активом позволяет выполнять важные задания по разработке систем массового участия. Идейные соображения высшего порядка, а также рамки и место обучения кадров позволяет оценить значение системы обучения кадров, соответствует насущным потребностям. Не следует, однако забывать, что консультация с широким активом способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям.</p>
		<p>Не следует, однако забывать, что консультация с широким активом способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям.</p>
		<form method="post" action="/about">
			<div class="form-group">
				<label for="exampleInputEmail1">Email address</label>
				<input type="email" name="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
				<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
			</div>
			<div class="form-group">
				<label for="exampleInputPassword1">Password</label>
				<input type="password" name="pass" class="form-control" id="exampleInputPassword1" placeholder="Password">
			</div>
			<div class="form-check">
				<input type="checkbox" name="check" class="form-check-input" id="exampleCheck1">
				<label class="form-check-label"  for="exampleCheck1">Check me out</label>
			</div>
			<button type="submit" class="btn btn-primary">Отправить</button>
		</form>
	</div>
</body>
</html>



index.js


let express = require('express');
var bodyParser = require('body-parser');
let app = express();

var urlencodedParser = bodyParser.urlencoded({ extended: false });

app.set('view engine', 'ejs');

app.use('/public', express.static('public'));


app.get('/', function(req, res){
	res.render('index');
});


app.get('/about', function(req, res){
	res.render('about');
});

app.post('/about', urlencodedParser, function(req, res){
	if (!req.body) return res.sendStatus(400);
	console.log(req.body);
	res.render('about');
});

app.get('/news', function(req, res) {
	res.render('news-common',{newParam1:'Param-1'});
});
app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4, paragraphs:['Параграф', 'Обычный текст', 'Числа: 3, 7, 24', 476]};
	res.render('news', {newsId: req.params.id, newParam: 535, obj: obj});
});
app.listen(8080);



Введем данные и нажмем отправить. В консоли мы увидим вывод этих данных (свойство - значение).



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

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

Изменим немного код в файле index.js


app.post('/about', urlencodedParser, function(req, res){
	if (!req.body) return res.sendStatus(400);
	console.log(req.body);
	res.render('about-success', {data: req.body});
});



Таким образом мы будем выводить страницу about-success.ejs и мы ее сейчас создадим в папке views. Вторым параметром мы передадим данные формы в виде объекта. - {data: req.body}


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>О нас.</title>
	<link href="https://fonts.googleapis.com/css?family=Poppins" rel="stylesheet">
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
	<link rel="stylesheet" type="text/css" href="/public/css/style.css">

</head>
<body>
	<% include blocks/header.ejs %>
	<div class="container">
		<h1>Hello, It is my first page on Node.js</h1>
		<h2>Заголовок второго уровня.</h2>
		<img src="http://www.chertpz.ru/assets/images/fotogallery_new/phormy_trub/Kvadrat.JPG" alt="">
		<a href="index">На главную</a>
		
		<p>Равным образом укрепление и развитие структуры способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям. Равным образом начало повседневной работы по формированию позиции требуют от нас анализа существенных финансовых и административных условий.</p>
	  <p>Спасибо</p>
	  <p>
	  	<b>Email:</b> <%= data.email %><br />
	  	<b>Pass:</b> <%= data.pass %><br />
	  	<b>isCheck:</b> <%= data.check %>
	  </p>
	</div>
</body>
</html>





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

Кроме этого было бы удобно отправлять эти данные на почту или сохранять в БД (базу данных).

Если вы хотите отправить их на почту. то в npm есть еще один пакет - Nodemailer. Этот пакет позволяет отправлять данные непосредственно на почту. Использовать его просто. И с помощью него вы можете получать по почте все данные формы, заполненной пользователем.

NodeJS предоставляет нам множество дополнительных пакетов. Например Express мы использовали для того, чтобы проще отслеживать ссылки и использовать шаблонизаторы. Body-parseer для того, чтобы принимать данные полученные из формы. Nodemailer - для отправки данных на почту.

Как получать данные из URL-строки.

Иногда нужно получить такой тип данных из адресной строки :

http://localhost:8080/news/12?filter-id&city=london


Разберем, как получить эти данные на примере вот этого кода из файла index.js:


app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4, paragraphs:['Параграф', 'Обычный текст', 'Числа: 3, 7, 24', 476]};
	res.render('news', {newsId: req.params.id, newParam: 535, obj: obj});
});



Просто выведем эти данные в консоль:


app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4, paragraphs:['Параграф', 'Обычный текст', 'Числа: 3, 7, 24', 476]};
	console.log(req.query);
	res.render('news', {newsId: req.params.id, newParam: 535, obj: obj});
});



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

{ filter: 'id', city: 'london' }




Это может быть иногда полезно.





                                                                                                                                                             

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

Основы Node JS ( II ).

В этой части мы создадим свой собственный сервер,разберем работу с потоками, функцию pipe и маршрутизацию.



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


Создание сервера на Node.js

Подключаем нужный модуль - http.

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

В переменную поместим вновь созданный сервер.

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

Все это внутрь нашей функции.

Теперь указываем порт.


let http = require('http');

let server = http.createServer( function (req, res) {
 res.writeHead( 200, {'Content-Type':'text/plain'});
 res.end('Hello. It is new server');
});
server.listen(8080,'localhost');
console.log('Server run on port 8080');



Откроем страницу http://localhost:8080/ в браузере и увидим наш текст.



Пока что наше приложение не реагирует на введение в адресную строку наименований.

Что бы мы не ввели, после http://localhost:8080/, страница никак не изменится.

В дальнейшем мы это исправим. а пока что мы сможем видеть ввод пользователем url в консоли:

Добавим строку console.log('URL страницы : ' + req.url); в начало функции.


let http = require('http');

let server = http.createServer( function (req, res) {
 console.log('URL страницы : ' + req.url);
 res.writeHead( 200, {'Content-Type':'text/plain'});
 res.end('Hello. It is new server');
});
server.listen(8080,'localhost');
console.log('Server run on port 8080');



Введем некий адрес и нажмем Enter.

В консоли мы увидим тот, адрес, что мы ввели в адресной строке и favicon.ico (это от Google Chrome), остальное - наш ввод.



Работа с потоками в Node JS.

Чтение файла.

Для того, чтобы понять, что такое потоки, проще всего представить, что вы смотрите большой фильм на youtube.

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

В Node.js мы можем также показывать большие объекты некими частями, подгружая их по мере прокрутки страницы (например), или по мере чтения большого текста.

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

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

Создадим новую переменную. Назовем как угодно.

let myReadShort = fs.createReadStream(path, options);

Первым параметром указывается файл, который мы хотим прочитать.

Путь к файлу указываем с помощью __dirname.

Второй параметр опционный.

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

В метод .createReadStream() уже встроен обработчик событий, поэтому. когда мы будем получать новые данные из файла мы их будем выводить в консоль.

Используем метод .on(). В нем мы отслеживаем событие 'data'. Это событие предустановленное и оно будет срабатывать, когда мы будем получать новый кусок данных из большого файла.

Вторым параметром пропишем функцию, которая будет принимать параметр (chunk - малый кусок данных, хотя можно дать свое название).


let fs = require('fs');

let myReadShort = fs.createReadStream(__dirname + '/big-text.txt');

myReadShort.on('data', function(chunk){
 console.log('Полученны новые данные \r \n' + chunk );
})



Если вы все сделали правильно то вы увидите постепенный вывод огромного текста в консоль.



Бывает, что для отображения кириллицы, стоит дописать опционный параметр в функцию fs.createReadStream(__dirname + '/big-text.txt', 'utf-8')

Запись данных потоками.

Отменим вывод в консоль наших chunk и добавим в код новую переменную


let fs = require('fs');

let myReadShort = fs.createReadStream(__dirname + '/big-text.txt','utf-8');
let myWriteShort = fs.createWriteStream(__dirname + '/news-big-text.txt');

myReadShort.on('data', function(chunk){
 console.log("Получены новые данные : ");
 myWriteShort.write(chunk);
});





Функция pipe(), работа с HTML и JSON.

Функция pipe().

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

Функция pipe() делает тоже самое и поэтому мы можем легко переписать наш код:


let fs = require('fs');

let myReadShort = fs.createReadStream(__dirname + '/big-text.txt','utf-8');
let myWriteShort = fs.createWriteStream(__dirname + '/news-big-text.txt');

// myReadShort.on('data', function(chunk){
//  console.log("Получены новые данные : ");
//  myWriteShort.write(chunk);
// });

myReadShort.pipe(myWriteShort);



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



Эта функция очень полезна для передачи данных на сервер.

Перенесем наш код локального сервера в этот файл, ниже.


let fs = require('fs');

let myReadShort = fs.createReadStream(__dirname + '/big-text.txt','utf-8');
let myWriteShort = fs.createWriteStream(__dirname + '/news-big-text.txt');

myReadShort.pipe(myWriteShort);

let http = require('http');

let server = http.createServer( function(req, res){
 res.writeHead(200, {'Content-Type':'text/plain; charset=utf-8'});
 res.end('Hello It is new server');
});
server.listen(8080, 'localhost');
console.log('Server run on 8080 port');



Теперь мы будем выводить не запись Hello It is new server, а целый файл.


let fs = require('fs');



let http = require('http');

let server = http.createServer( function(req, res){
 res.writeHead(200, {'Content-Type':'text/plain; charset=utf-8'});
 let myReadShort = fs.createReadStream(__dirname + '/big-text.txt','utf-8');

  myReadShort.pipe(res);

});
server.listen(8080, 'localhost');
console.log('Server run on 8080 port');





Очень много текста на страницу вывелось частями (оптимизировано).

Вывод HTML.

Создадим простой html - файл.

Можно даже добавить стили.

Файл index.html


<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Заголовок страницы.</title>
 <style>
  body {
   background-color: #fafafa;
   font-family: Lato;
   font-size: 18px;
   color:#2A2A2A;
  }
  .container {
   margin: 10px 40px;
  }
 </style>
</head>
<body>
 <div class="container">
 <h1>Hello, It is my first page on Node.js</h1>
 <h2>Заголовок второго уровня.</h2>
 <p>Равным образом укрепление и развитие структуры способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям. Равным образом начало повседневной работы по формированию позиции требуют от нас анализа существенных финансовых и административных условий.</p>
 <h3>третьего уровня заглавие.</h3>
 <p>Значимость этих проблем настолько очевидна, что консультация с широким активом позволяет выполнять важные задания по разработке систем массового участия. Идейные соображения высшего порядка, а также рамки и место обучения кадров позволяет оценить значение системы обучения кадров, соответствует насущным потребностям. Не следует, однако забывать, что консультация с широким активом способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям.</p>
 <p>Не следует, однако забывать, что консультация с широким активом способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям.</p>
 </div>
</body>
</html>



Теперь возникает вопрос - как это вывести на страницу?

text/plain - вывод просто текста

text/html - вывод html.

Вместо файла, который читаем - название нашего файла - index.html


let fs = require('fs');



let http = require('http');

let server = http.createServer( function(req, res){
 res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'});
 let myReadShort = fs.createReadStream(__dirname + '/index.html','utf-8');

  myReadShort.pipe(res);

});
server.listen(8080, 'localhost');
console.log('Server run on 8080 port');





Мы вывели весь наш файл со стилями. И главное. то что мы вывели его постепенно. Если бы страница была очень большая, то она выводилась бы частями (chunk) и вывод не мешал бы пользователю.

Вывод JSON.

'Content-Type':'application/json' -вывод JSON формата на страницу.

Сам объект

Конвертировать его в строку на выводе.


let fs = require('fs');

let http = require('http');

let server = http.createServer( function(req, res){
 console.log('URL страницы : ' + req.url);
 res.writeHead(200, {'Content-Type':'application/json; charset=utf-8'});

 let obj = {
  model:'Audi',
  speed:'134 km',
  wheels: 4
 };
 res.end(JSON.stringify(obj));
});
server.listen(8080, 'localhost');
console.log('Server run on 8080 port');





Маршрутизация Node JS

Будем выдавать разные html-страницы на разные url-запросы.


let fs = require('fs');
let http = require('http');

let server = http.createServer(function(req, res){
 console.log('URL страницы : ' + req.url);
 if (req.url === '/index' || req.url === '/') {
 res.writeHead(200,{'Content-Type':'text/html; charset=utf-8'});
 fs.createReadStream(__dirname + '/index.html').pipe(res);
 }
});

server.listen(8080, 'localhost');
console.log('Server run on 8080 port');



Если сейчас попробовать в адресную строку ввести какой то адрес отличный от/ или /index, то мы получим долгую загрузку и ничего более.

Точно так же можно подключить еще одну страницу:

Файл about.html


<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Заголовок страницы.</title>
 <link href="https://fonts.googleapis.com/css?family=Poppins" rel="stylesheet">
 <style>
  body {
   background-color: #77F39E;
   font-family: 'Poppins', sans-serif;
   font-size: 1.2rem;
   color:#2f2f2f;
  }
  .container {
   margin: 10px 40px;
   padding: 20px;
  }
  img {
   float: left;
   margin-right: 20px;
   width: 300px;
   height: 300px;
  }
 </style>
</head>
<body>
 <div class="container">
 <h1>Hello, It is my first page on Node.js</h1>
 <h2>Заголовок второго уровня.</h2>
 <p>Равным образом укрепление и развитие структуры способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям. Равным образом начало повседневной работы по формированию позиции требуют от нас анализа существенных финансовых и административных условий.</p>
 <h3>третьего уровня заглавие.</h3>
 <p>Значимость этих проблем настолько очевидна, что консультация с широким активом позволяет выполнять важные задания по разработке систем массового участия. Идейные соображения высшего порядка, а также рамки и место обучения кадров позволяет оценить значение системы обучения кадров, соответствует насущным потребностям. Не следует, однако забывать, что консультация с широким активом способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям.</p>
 <p>Не следует, однако забывать, что консультация с широким активом способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям.</p>
 </div>
</body>
</html>



Такая маршрутизация сложна для чтения, но это только потому, что мы не используем фреймворки (например Express). Это чистый код нужен для понимания того, как работает маршрутизация на NodeJS





                                                                                                                                                             

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

Основы Node JS ( I ).

Основы работы с Node JS. Часть - 1.

Node.js — это среда выполнения JavaScript, построенная на JavaScript-движке V8 из Chrome. В основе Node.js лежит событийно-управляемая модель с неблокирующими операциями I/O, что делает её легкой и эффективной.



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


Другими словами: Node.js предлагает вам возможность писать невероятно производительный серверный код с использованием JavaScript. Как говорится в официальном описании: Node.js — это среда выполнения, использующая тот же JavaScript-движок V8, который вы можете найти в браузере Google Chrome.

Функции

  1. Простая:


  2. 
    function hello(){
     console.log('Hello Proger');
    };
    
    hello();
    
    


  3. Именованная:


  4. var someName = function(){
     console.log("SomeName Function");
    };
    someName();
    
    


  5. Функция из функции:


  6. 
    function call(func){
     func();
    };
    
    call(someName);
    
    


Модули

В файл array.js запишем:


let array_counter = function ( array ) {
 return 'В массиве находится ' + array.length + ' элементов.';
};

console.log( array_counter( [ 1, 33, 45, 23, 7, 31, 40 ] ) );

Подключение к index.js

require('./array');



Если мы подключаем какой-то файл, то это не значит, что мы можем использовать все функции из этого файла.

Например, если вывод в консоль перенести из файла array.js в index.js, то получим ошибку.

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

  1. Используется метод modelr.exports = name_function;
  2. Директиве require('./array'); присвоить переменную.
Файл index.js


let counter = require('./array');

console.log( counter( [ 1, 33, 45, 23, 7, 31, 40 ] ) );



Файл array.js


let array_counter = function ( array ) {
 return 'В массиве находится ' + array.length + ' элементов.';
};

module.exports = array_counter;



Несколько функций из одного модуля.


let array_counter = function ( array ) {
 return 'В массиве находится ' + array.length + ' элементов.';
};


let some_value = 324;

let multiplay = function(x, y){
 return `Число ${x} умножить на ${y} = ${x * y} `;
};

module.exports.array_counter = array_counter;
module.exports.some_value = some_value;
module.exports.multiplay = multiplay;



Файл index.js


let things = require('./things.js');

console.log( things.array_counter( [ 1, 33, 45, 23, 7, 31, 40 ] ) );

console.log(things.some_value);

console.log(things.multiplay(4, 8));



Упростим


module.exports.array_counter = function ( array ) {
 return 'В массиве находится ' + array.length + ' элементов.';
};


module.exports.some_value = 324;

module.exports.multiplay = function(x, y){
 return `Число ${x} умножить на ${y} = ${x * y} `;
};




let array_counter = function ( array ) {
 return 'В массиве находится ' + array.length + ' элементов.';
};


let some_value = 324;

let multiplay = function(x, y){
 return `Число ${x} умножить на ${y} = ${x * y} `;
};

module.exports = {
array_counter : array_counter,
some_value : some_value,
multiplay : multiplay
};





Отслеживание событий в Node

Подключение встроенных модулей.

Все делается через директиву require('name_modele');

let events = require('events');

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

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

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

let myEmit = new events.EventEmitter();

Для события используем метод .on(). Первым аргументом - название события, которое отслеживаем. Вторым аргументом запишем функцию. которая будет срабатывать на это событие.

Например:

myEvent.on('click', function(){console.log('Event click'});

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


let events = require('events');

let myEmit = new events.EventEmitter();

myEmit.on('some_event', function(text){
 console.log(text);
});

myEmit.emit('some_event', 'Обработчик событй сработал');





Модуль позволяющий наследовать события - Util

  1. Создали переменную в которую присвоили модуль util.
  2. Создадим конструктор.
  3. После этого можно использовать модуль util, чтобы все объекты созданные на основе этого конструктора Cars унаследовали обработчик событий.


util.inherits(ctor, superCtor);

Первым параметром указываем конструктор, который будет наследовать. Вторым - что конкретно наследовать.

util.inherits(Cars, events.EventEmitter);

Круглые скобки событию не надо.

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


let events = require('events');
let util = require('util');

let Cars = function(model){
 this.model = model;
}

util.inherits(Cars, events.EventEmitter);

let bmv = new Cars('BMW');
let audi = new Cars('Audi');
let volvo = new Cars('Volvo');



На самом деле util.inherits просто позволяет наследовать прототипы от одного конструктора к другому (не только конструктор событий).

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

  1. Создадим массив cars, в который пометим все объекты, которые мы создали.


  2. let cars = [bmv, audi, volvo];

  3. Теперь ы легко можем перебирать массив и объекты в нем.


  4. cars.forEach(function(car){ car.on('speed', function(text){ console.log( `Auto ${car.model} speed is $(text}`)); }); });

  5. Вызываем события.


bmw.emit('speed', '245.3 km');

Код полностью index.js


let events = require('events');
let util = require('util');

let Cars = function(model){
 this.model = model;
}

util.inherits(Cars, events.EventEmitter);

let bmw = new Cars('BMW');
let audi = new Cars('Audi');
let volvo = new Cars('Volvo');

let cars = [bmw, audi, volvo];

cars.forEach(function(car){
 car.on('speed', function(text){
  console.log( 'Auto ' + car.model + ' speed is ' + text);
 });
});

bmw.emit('speed', '245.3 km');






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


bmw.emit('speed', '245.3 km');
volvo.emit('speed', '198 km');
audi.emit('speed', '259 km');





Запись и чтение файлов

Синхронное чтение.

Создадим text.txt файл из которого будем что-то читать.

Добавим в него текст:

Файл text.txt.


Ура! Вы меня прочитали!
You read this text.



При этом важно указать кодировку, иначе кириллицу отображать не будет.



Читать и записывать файлы поможет модуль fs. Вызываем его.

fs.readFileSync(path, options);

Первый параметр - файл и путь к нему.

Второй - кодировка. В нашем случае - 'utf8'

Пока не прочитаем файл, код ниже не сработает.

Поместим весь этот текст в переменную file_readed


let fs = require('fs');

let file_read = fs.readFileSync('text.txt', 'utf8');

console.log(file_read);





Синхронная запись.

Используем тот же модуль, но функцию

fs.writeFileSync(path, data, options);

Первый параметр - название файла куда записывать. Если его нет, то он будет создан.Например some_new_file.txt

Второй параметр - данные (текст). Можно указать просто имя переменной, в которой этот текст.

Например:

let message = 'Hello World - Привет Мир\n' + file_read;


let fs = require('fs');

let file_read = fs.readFileSync('text.txt', 'utf8');

let message = "Hello World -  Привет Мир \r\n" + file_read;

fs.writeFileSync('some_new_file.txt', message);



Запустим

node index


Ничего не произойдет в консоли, но зато появится новый файл some_new_file.txt в нашей директории.

Откроем и там:



Асинхронная.

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

Чтение файлов асинхронное

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

В этой функции первым параметром err - ошибка. Если не получится прочитать файл обратимся к ней, а вторым data - непосредственно данные.


let fs = require('fs');

fs.readFile('text.txt', 'utf8', function(err, data){
 console.log(data);
});

console.log('Test');



Вывод слова Test для наглядности асинхронности кода.



Запись файла асинхронная

Используется почти такая же конструкция, что и для чтения.

Вторым параметром пойдет тот текст, который мы хотим записать. Можно его поместить в переменную, как и с синхронными функциями.

Третьим параметром функция в которой можно ничего не возвращать.


let fs = require('fs');

fs.readFile('text.txt', 'utf8', function(err, data){
 console.log(data);
});

fs.writeFile('some.txt', 'Hello Programmers from me', function(err, data){});

console.log('Test');





Удаление файлов. Создание и удаление директории.

Удаление файлов.

Используется модуль fs

let fs = require('fs');

fs.unlinkSync(path);
fs.unlink(path, callback);


Первый параметр название файла который удаляем, или путь.

Второй - Функция, которая будет срабатывать, после завершения удаления конкретного файла.

В нее можно ничего не передавать, но она нужна, чтобы не было ошибки.


let fs = require('fs');

fs.unlink('text1.txt', function(){
 console.log('File text1 deleted');
});





Создание директории.


fs.mkdirSync(path, mode);
fs.mkdir(path, mode, callback);


Первый параметр - путь (название папки)

Второй - не обязательный при синхроне.


let fs = require('fs');

fs.mkdir('new-test', function(){
 fs.writeFile('./new-test/some-new.txt', 'Hello world!', function(){
  console.log('everything is done');
 });
});





Удаление.

Удалить можно только пустую папку.

fs.rmdirSync(path);
fs.rmdir(path, callback);



let fs = require('fs');

fs.unlink('./new-test/some-new.txt', function(){
  fs.rmdir('./new-test', function(){
  console.log('Удалили  файл и папку');
 });
});









                                                                                                                                                             

пятница, 28 сентября 2018 г.

ES6: Символы (symbols) (XV).

Symbol

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

Symbol - специальный тип данных с помощью которого можно создать уникальный идентификатор свойств объектов. Именно для этого и придумали символы.



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


Символы - уникальные и неизменные значения.

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

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

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

Символы поддерживаются всеми современными браузерами и последними версиями ноды. Для поддержки старых версий на сайте Babel

Пройти по пути сайт Babel -> Usage ->Polyfill



Установить через npm в папку проекта и подключить в файле index.html

<script src="node_modules/babel-polyfill/dist/polyfill.min.js"></script>

Откроем в редакторе файл symbol.js, подключим его к нашему файлу index.html, точно так же, как мы это делали в предыдущих частях руководства.

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

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

Создадим переменную и в нее пометим результат вызова функции Symbol.

Результат выведем в консоль.


let symbol = Symbol();

console.log(symbol);



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



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


let symbol = Symbol();

console.log( typeof symbol);





Заметьте, что при создании нового символа мы не используем слово new.

Если мы, все таки попробуем, то получим ошибку.


let symbol = new Symbol();

console.log( typeof symbol);





Это происходит потому, что Symbol не является конструктором.

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


let symbol = Symbol('name');

console.log(symbol);





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


let symbol = Symbol('name');
let symbol2 = Symbol('name');

console.log(symbol);
console.log(symbol2);





При создании символов мы увидели одинаковые сообщения. но при этом символы не равны!

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

Таким образом имя символа мы используем для обращения к нему.

Создать два одинаковых символа нельзя!

Посмотреть на внутренние значения символа нам тоже не удастся.

Еще одним методом создания символов является метод Symbol.for.


let symbol = Symbol.for('name');

console.log(symbol);



В консоли получим тоже сообщение. что и при первом методе создания символа.



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


let symbol = Symbol.for('name');
let symbol2 = Symbol.for('name');

console.log(symbol === symbol2);



В консоли получим значение: true.

Первый и второй символы - это один и тот же символ.

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

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

Символы, созданные функцией Symbol не попадают в этот реестр и их нельзя найти с помощью метода for.

Имя символа можно получить методом keyFor.


let symbol = Symbol.for('name');
let name = Symbol.keyFor(symbol);

console.log(name);




В консоли мы увидим - name.

Если в метод .for не передать имя, то получим ошибку

let symbol = Symbol.for();

Будет ошибка!

Использование символов.

В ES5 свойства объектов должны быть строками.

В ES6 они могут быть строками и символами.

Создадим объекта и в качестве второго свойства присвоим символ.


let user = {
 name : 'John',
 [Symbol('password')] : 'r89n123'
};

console.log(user.password);



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

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

Попробуем посмотреть на все свойства объекта -


let user = {
 name : 'John',
 [Symbol('password')] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));



Мы увидим только name.



Попробуем еще и

console.log(Object.getOwnPropertyNames(user));



Как же получить доступ к паролю?

Давайте попробуем использовать метод .for().


let user = {
 name : 'John',
 [Symbol('password')] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

let password = user[Symbol.for('password')];

console.log(password);



И в консоли опять - undefined.



Если мы создаем символ с помощью функции Symbol(), то он не попадает в глобальный реестр и мы не сможем его найти с помощью метода .for()


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

Но если у объекта указать с .for()


let user = {
 name : 'John',
 [Symbol.for('password')] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

let password = user[Symbol.for('password')];

console.log(password);





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

Этот метод находится у объектов Object и называется getOwnPropertySymbols


let user = {
 name : 'John',
 [Symbol.for('password')] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

let password = user[Symbol.for('password')];

console.log(password);

console.log(Object.getOwnPropertySymbols(user));





Даже если мы уберем .for у объекта, то все равно мы увидим тоже самое сообщение.



А если убрать и имя, то


let user = {
 name : 'John',
 [Symbol()] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

let password = user[Symbol.for('password')];

console.log(password);

console.log(Object.getOwnPropertySymbols(user));



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



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


let password = Symbol();

let user = {
 name : 'John',
 [password] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

// let password = user[Symbol.for('password')];

// console.log(password);

console.log(Object.getOwnPropertySymbols(user));





Результат будет тот же, но теперь символ хранится в переменной.

Смволы были добавлены в язык не для того, чтобы что-то спрятать. Они были добавлены для того, чтобы избежать конфликта имен свойств.

Так мы можем добавить нашему объекту еще одно свойство password.


let password = Symbol();

let user = {
 name : 'John',
 [password] : 'r89n123',
 password: 'a9b9c9n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

// let password = user[Symbol.for('password')];

// console.log(password);

console.log(Object.getOwnPropertySymbols(user));



В консоли:



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

При желании мы можем его получить.

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

Эти символы называют - Well-known symbols или хорошо известные символы.

Одним из них является Symbol.iterator. Благодаря этому символу мы можем получить доступ к внутреннему методу объекта.

Выглядит это так:

У объекта должно быть свойство Symbol.iterator. Это свойство является методом, поэтому - круглые скобки и фигурные скобки .

Теперь мы можем добавить объекту свойство iterator и никакого конфликта не будет.


let object = {
 iterator: 0,
 [Symbol.iterator](){}
}



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

Об этом мы поговорим уже в следующем посте.





                                                                                                                                                             


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