Translate

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

Показаны сообщения с ярлыком ES6. Показать все сообщения
Показаны сообщения с ярлыком ES6. Показать все сообщения

четверг, 4 октября 2018 г.

Блог на NodeJS Express MongoDB ( II ).





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


Создание REST API роутов

В корне проекта создадим папку - routes.

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

В файле сразу подключаем express - const express = require('express')

Далее создадим переменную, которая добывается из функции экспресс - Router()

const router = express.Router()

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

module.exports = router

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

Для этого мы должны перейти в файл app.js, где мы описываем сервер и подключит данный роутер.

const postRouter = require('./routes/post.js').


const express = require('express')
const mongoose = require('mongoose')
const path = require('path')
const postRouter = require('./routes/post')
const keys = require('./keys')

const port = process.env.PORT || 5000
const clientPath = path.join(__dirname, 'client')

mongoose.connect(keys.mongoURI)
			.then(() => console.log('MongoDB connected'))
			.catch(err => console.error(err))	
const app = express()
app.use(express.static(clientPath))
app.listen(port,()=>{
	console.log(`Server run on ${port} port`)
})



Теперь, для того чтобы использовать наш роутер, мы должны, после того, как определили объект нашего приложения =>const app = express() (ниже) написать команду

app.use('', postRouter)

Для того чтобы применить какой то роут и экспресc понимал ссылки.

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

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

Теперь нужно подумать какой префикс нам здесь написать?

По сути, у нас будет часть сервера, которая будет отдавать клиентскую сторону - index.html и у нас будет часть сервера, которая будет отвечать за REST API. Соответственно, все что будет делаться через REST API мы можем начинать с префикса /api/ и далее, так как у нас идет здесь идет работа именно с постами, мы можем указывать сущьности - например post

app.use('/api/post', postRouter)

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

Перейдем в файл post.js

По сути для нашего приложения важно реализовать три действия:
  1. - получит все посты, которые есть в БД
  2. - создать новый пост
  3. - реализовать удаление какого-то поста
В REST API для того, чтобы получать что-то мы используем http-запросы с методом get.

Для того, чтобы реализовать метод get в экспрессе мы обращаемся к роутеру (router) и вызываем у него метод get.

Здесь в качестве параметра мы просто указываем слэш - '/'.

Вторым параметром указываем callback-функцию, которая принимает два параметра ( req -request - запрос res - response - ответ.)

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


router.get('', (req, res) => {
	
})



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

У нас есть некоторый префикс - '/api/post' и это означает, что мы будем видеть запрос следующего характера:

http://localhost:5000/api/post

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

Похожая ситуация у нас будет реализована еще для двух методов.

В REST API если мы хотим что-то создать, то мы используем метод POST, удалить - DELETE.

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

routes/post.js


const express = require('express')

const router = express.Router()
// http://localhost:5000/api/post GET
router.get('', (req, res) => {

})
// http://localhost:5000/api/post POST
router.post('', (req, res) => {
	
})
// http://localhost:5000/api/post DELETE
router.delete('', (req, res) => {
	
})

module.exports = router



Сейчас, давайте попробуем описать метод GET с помощью которого мы хотим что-то получить.

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

const Post = require('../models/Post')

Теперь с помощью этого объекта мы уже можем работать с БД.

Для того, чтобы получить все сущьности из БД, нам нужно в методе GETобратиться к и вызвать у него метод find(), передав в метод пустой объект. Это означает, что мы будем требовать все посты без каких либо условий.


router.get('', (req, res) => {
	Post.find({})
})



Данная операция является асинхронной. Она нам будет возвращать некий промис мы его можем ченить с помощью метода .then и после этого как-то обрабатывать.


router.get('', (req, res) => {
	Post.find({}).then((posts)=>{
 	//что-то делать...	
 })
})



Мы пойдем более современным путем. Так как мы работает на платформе NodeJS, которая не требует понимания разных браузеров, то здесь можно использовать все новшества современного JS ES6.

Поэтому мы смело можем использовать синтаксис - async/await.

Вместо того, чтоб так ченить промисы.

Мы можем сказать NodeJS, что данная функция будет являться асинхронной и поставить вначале нее async

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

const posts = await Post.find({})

Эта конструкция полностью идентична

	Post.find({}).then((posts)=>{
          // ...
	})



При этом мы написали полностью асинхронный код и у нас нет вложенных функций.

Таким образом мы получили:


const express = require('express')

const router = express.Router()

const Post = require('../models/Post')
// http://localhost:5000/api/post GET
router.get('', async(req, res) => {
const posts = await Post.find({})
})
// http://localhost:5000/api/post POST
router.post('', (req, res) => {
	
})
// http://localhost:5000/api/post DELETE
router.delete('', (req, res) => {
	
})

module.exports = router



Думаем над тем. что нам делать еще в методе GET По сути, мы должны что-то отдать клиенту (список постов). Для того, чтобы ответить клиенту мы можем воспользоваться объектом res, затем указать статус

res.status(200) и с помощью метода json указать те данные, которые мы хотим отправить обратно - posts.

res.status(200).json(posts)


const express = require('express')

const router = express.Router()

const Post = require('../models/Post')
// http://localhost:5000/api/post GET
router.get('', async(req, res) => {
	const posts = await Post.find({})
	res.status(200).json(posts)
})
// http://localhost:5000/api/post POST
router.post('', (req, res) => {
	
})
// http://localhost:5000/api/post DELETE
router.delete('', (req, res) => {
	
})

module.exports = router



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

Метод POST

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

Создадим переменную postData и это будет объект с полями title и text. Здесь мы будем с клиента отправлять данные в БД. Для сбора данных и нужны эти поля.

Теперь эти данные нужно обработать. Это сделать просто. У нас есть объект req с помощью которого будет сделан запрос и сказать ему, что например, title хранится в req.body.title.


router.post('', (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
})



Теперь у нас есть данные необходимые для создания нового поста в базе и мы можем создать новый пост с помощью модели Post на основе данных postData.

const post = new Post(postData)

И после этого нам нужно сохранить это все в БД. Для этого можно просто написать:

await post.save()

И сделать функцию асинхронной:


router.post('', async (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
	const post = new Post(postData)
	await post.save()
})



Этой строкой -

await post.save()

мы будем ждать, когда код сохранится на сервере. Далее объект post изменится, потому что придет ответ с БД и у нас будет уникальный ID, который нам выдаст MongoDB и у нас определится дата. когда был создан пост..

И теперь мы можем ответить (res)клиенту оперируя теми данными, которые мы получили с БД.

В RESTAPI если мы что-то создаем, то используем статус 201, а далее методом json мы указываем. чо будем обратно возвращать post.

res.status(201).json(post)


// http://localhost:5000/api/post POST
router.post('', async (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
	const post = new Post(postData)
	await post.save()
	res.status(201).json(post)
})



Метод DELETE

Он будет тоже асинхронным, как и предыдущие методы. (Добавим async).

В этом методе нам нужно будет удалить пост по ID. Поэтому здесь уже не подойдет такой url - http://localhost:5000/api/post, потому что нам в нем надо передать id того поста, который мы хотим удалить. Например id =34;

http://localhost:5000/api/post/34

Эта часть будет динамическая.

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

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

Теперь нам нужно с помощью модели Post вызвать метод remove(), который позволяет нам что-то удалять из базы. и далее мы говорим условия - какой именно пост мы хотим удалить в объекте. Мы хотим удалить пост у которого _id === id который придет в роуте. А этот параметр хронися в объекте запроса req (req.params.is)

Так как функция асинхронная, то мы ее должны подождать - await


router.delete('/:id', async (req, res) => {
	await Post.remove({_id: req.params.id})
})



Как только удалится нужный нам пост мы можем ответить клиенту статусом 200 и в json отправить мессендж -"Удалено"


router.delete('/:id', async (req, res) => {
	await Post.remove({_id: req.params.id})
	 res.status(200).json({
	 	message: 'Удалено'
	 })
})



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

Файл post.js


const express = require('express')

const router = express.Router()

const Post = require('../models/Post')
// http://localhost:5000/api/post GET
router.get('/', async (req, res) => {
	const posts = await Post.find({})
	res.status(200).json(posts)
})
// http://localhost:5000/api/post POST
router.post('/', async (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
	const post = new Post(postData)
	await post.save()
	res.status(201).json(post)
})
// http://localhost:5000/api/post DELETE
router.delete('/:id', async (req, res) => {
	await Post.remove({_id: req.params.id})
	 res.status(200).json({
	 	message: 'Удалено'
	 })
})

module.exports = router



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

Тестирование серверной части.

Всё, что относится к фронтенд части хранится в папке client. Там, пока что, один файл - index.html

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

Подключаем css, material icons и скрипт js к нашему index.html файлу через CDN (ссылки на сайте) . После скрипта материалайза подключаем наш скрипт index.js, который мы создадим в той же папке.

В нем мы будем вести разработку на нативном JS.

В файле index.html создадим div - контейнер, которому зададим стиль, чтобы он не прилипал к верху экрана и в него мы будем выводить посты.


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	 <!-- Compiled and minified CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">	
  <!--Import Google Icon Font-->
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
	<title>FS-Blog</title>
   <!--[if IE]>
   <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <![endif]-->
</head>
<body>
	<div class="container center" style="padding-top: 50px;">
		<div class="row">
			<div class="col s12 m8 offset-m2 lg6 offset-3" id="post">
				<div class="card">
	        <div class="card-content">
	          <span class="card-title">Post Title</span>
	          <p>I am a very simple card. I am good at containing small bits of information.</p>
	          <small>12.12.1212</small>
	        </div>
	        <div class="card-action">
						<button class="btn btn-small red">
							<i class="material-icons">Delete</i>
						</button>	
	        </div>
	      </div>
			</div>
		</div>
	</div>


	<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
	<script src="index.js"></script>
</body>
</html>



Запускаем сервер

npm run dev


Переходим на сайт localhost:5000 и видим:



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

Первое - нам нужно сделать некий компонент, который будет генерировать html-код определенного поста. Поэтому, все что отмечено красным вырезаем и переносим в файл index.js


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	 <!-- Compiled and minified CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">	
  <!--Import Google Icon Font-->
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
	<title>FS-Blog</title>
   <!--[if IE]>
   <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <![endif]-->
</head>
<body>
	<div class="container center" style="padding-top: 50px;">
		<div class="row">
			<div class="col s12 m8 offset-m2 lg6 offset-3" id="post">
		<div class="card z-depth-4">
	        <div class="card-content">
	          <span class="card-title">Post Title</span>
	          <p>I am a very simple card. I am good at containing small bits of information.</p>
	          <small>12.12.1212</small>
	        </div>
	        <div class="card-action">
						<button class="btn btn-small red">
							<i class="material-icons">Delete</i>
						</button>	
	        </div>
	      </div>
			</div>
		</div>
	</div>


	<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
	<script src="index.js"></script>
</body>
</html>



И так как здесь у нас нативный JS, то мы создадим подобие компонента в переменной card


const card = post => {
	return `
		<div class="card z-depth-4">
	           <div class="card-content">
	            <span class="card-title">${post.title}</span>
	            <p>${post.text}</p>
	            <small>${post.date}</small>
	           </div>
	          <div class="card-action">
		    <button class="btn btn-small red">
			<i class="material-icons">Delete</i>
		    </button>	
	        </div>
	      </div>
	`
}



Функция, которая принимает post и отдает html разметку. Данные в которой мы выводим как переменные.

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

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

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

Допустим, что это будет класс PostApi. У него будет несколько методов.

Первый статический static fetch(), в который мы не будем передавать параметры. Этим методом мы будем делать запрос на получение всех наших постов.

В JS есть нативная функция fetch(), с помощью нее мы как раз и можем делать запросы.

Первым параметром в эту функцию нам надо передать url по которому мы хотим сделать запрос.

Для этого мы создадим новую константу - const BASE_URL='api/post' - Это та самая строчка. которая обозначена в файле app.js.

Вторым параметром мы указываем метод с помощью которого мы хотим сделать запрос. В нашем случае, когда мы хотим получить список всех потов это метод GET. ({method: get}.

Далее, метод fetch() возвращает промис и в методе .then мы можем привести тот формат который прилетает к нам с сервера и обрабатывается JS, привести в понятный формат объектов. Поэтому - res=>res.json() и все это вернем из метода fetch().


const BASE_URL = '/api/post'

clss PostApi {
	static fetch(){
		return fetch(BASE_URL, {method: get}).then(res=>res.json())
	}
}



И теперь в какой момент нам необходимо сделать запрос?

При загрузке страницы.

На документ поставим обработчик события.

document.addEventListener('DOMContentLoaded', () => {
	
})


Как только запускаем приложение нам нужно сделать запрос к бекенду, поэтому мы обращаемся к PostApi.fetch и вызываем метод .fetch() и так как он возвращает промис, то .then(). В этом методу мы будем получать объект backendPosts. То есть это будет уже тот массив, который прилетит от сервера. И теперь, нам нужно просто вывести все эти посты в html.

Для этого создадим наверху файла переменную let posts = []. Именно в ней мы будем хранить все посты, которые у нас есть.

Когда мы получим наши посты то в эту переменную мы положим содержимое backendPosts на котором вызовем метод concat, для предотвращения проблем мутаций.

Он просто сгенерирует дубликат данного массива.


const BASE_URL = '/api/post'
let posts =[]
clss PostApi {
	static fetch(){
		return fetch(BASE_URL, {method: 'get'}).then(res=>res.json())
	}
}

document.addEventListener('DOMContentLoaded', () => {
	PostApi.fetch().then(backendPosts => {
		posts = backendPosts.concat()
	})
})



Теперь, когда у нас есть список всех постов с бэкенда и нам остается их отрендерить.

Для этого создадим функцию renderPosts(posts) куда и передадим эти посты.

Функцию опишем ниже. По умолчанию она будет принимать пустой массив - _posts=[]

У нас есть id="posts" в файле index.html куда нам нужно выводить наши посты.

$ - просто обозначает, что это некоторый элемент.


function renderPosts(_posts=[]) {
	const $posts = document.querySelector('#posts')

}



Далее, проверим. Если длина массива пришедшего в функция больше 0, то есть у нас есть некоторые посты, то мы будем генерировать карточки. Иначе мы просто выведем сообщение "Постов пока нет".

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

Мы можем обратиться к локальной переменной _posts и далее с помощью метода .map() мы на каждой итерации будем получать определенный post (это объект) и на выходе вернуть html, то есть вызвать функцию card(post)

Преобразуем массив к строке методом .join(' '). Через пробел.


function renderPosts(_posts=[]) {
	const $posts = document.querySelector('#posts')
	if(_posts.length > 0) {
		$posts.innerHTML = _posts.map(post=> card(post)).join()	 
	} else {
		$posts.innerHTML = `
Постов пока нет.
` } }


Сохраняем и обновляем страницу Идем на вкладку Networkв в консоли.



Видим, что "Постов пока нет", а в запросах - url совпадает и метод GET, и получаем пустой массив post



С выводом постов мы разобрались.

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

Имитируем задержку сервера функцией setTimeout пред рендерингом постов, а на это время сделаем показ индикатора загрузки.


document.addEventListener('DOMContentLoaded', () => {
	PostApi.fetch().then(backendPosts => {
		posts = backendPosts.concat()
		setTimeout(()=>{
		renderPosts(posts)
		}, 2000)			
	})
})



Прелоудер возьмем на сайте materializecss.com

Скопируем там готовый код прелоудера и добавим его в наш див поста в файле index.html

Файл index.html полностью:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	 <!-- Compiled and minified CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">	
  <!--Import Google Icon Font-->
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
	<title>FS-Blog</title>
   <!--[if IE]>
   <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <![endif]-->
</head>
<body>
	<div class="container center" style="padding-top: 50px;">
		<div class="row">
			<div class="col s12 m8 offset-m2 lg6 offset-3" id="posts">
				<div class="preloader-wrapper small active">
					<div class="spinner-layer spinner-green-only">
						<div class="circle-clipper left">
							<div class="circle"></div>
						</div><div class="gap-patch">
							<div class="circle"></div>
						</div><div class="circle-clipper right">
							<div class="circle"></div>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>


	<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
	<script src="index.js"></script>
</body>
</html>



Файл index.js полностью:



const card = post => { return ` <div class="card z-depth-4"> <div class="card-content"> <span class="card-title">${post.title}</span> <p>${post.text}</p> <small>${post.date}</small> </div> <div class="card-action"> <button class="btn btn-small red"> <i class="material-icons">Delete</i> </button> </div> </div> ` } const BASE_URL = '/api/post' let posts =[] class PostApi { static fetch(){ return fetch(BASE_URL, {method: 'get'}).then(res=>res.json()) } } document.addEventListener('DOMContentLoaded', () => { PostApi.fetch().then(backendPosts => { posts = backendPosts.concat() setTimeout(()=>{ renderPosts(posts) }, 2000) }) }) function renderPosts(_posts=[]) { const $posts = document.querySelector('#posts') if(_posts.length > 0) { $posts.innerHTML = _posts.map(post=> card(post)).join() } else { $posts.innerHTML = `<div class="center">Постов пока нет.</div>` } }


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





                                                                                                                                                             

понедельник, 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