Всем привет, так что же это такое за функции генераторы спросите вы и как их использовать?!
Функция генератор чем то напоминает обычную функцию , но возвращает не одно значение, а несколько по одному. И сразу рассмотрим пример:
function* generator_function(){
yield 1;
yield 2;
yield 3;
}
var generator = generator_function();
console.log(generator.next().value);
console.log(generator.next().value);
console.log(generator.next().value);
Сморить в консоль и видим:
1
2
3
Теперь давайте разбираться что я здесь такого понаписал!
Во первых функция генератор определяется с помощью данного выражения function* ,во вторых для того чтобы нам вызвать функцию генератор необходимо воспользоваться методом next();, в третьих при каждом вызове функции генератора в ее теле выполняется код до ключевого слова yield, в четвертых все что находится между yield и точкой с запятой будет возвращено, в пятых для того чтобы принять, то что возвращает функция генератор мы должны в вызов функции дописать метод value;
Довольно запутанно не правда ли, но сейчас мы с вами все подробно разберем.
И так, как вы уже наверное догадались на каждый вызов в функции генератора она нам возвращает следующую итерацию, то есть у нас в генераторе определено три итерации:
function* generator_function(){
//Первая итерация
yield 1; //Конец первой итерации возвращаемое значение 1
//Вторая итерация
yield 2; //Конец второй итерации возвращаемое значение 2
//Третья итерация
yield 3; //Конец третьей итерации возвращаемое значение 3
}
Мы с вами вызываем функцию генератор три раза и сразу же выводим, то что она возвращает в консоль:
console.log(generator.next().value);//Первый вызов нам возвращается результат первой итерации и так далее
console.log(generator.next().value);
console.log(generator.next().value);
Мы можем также, ничего не возвращать, вывести значения в консоль через сам генератор:
function* generator_function(){
console.log(1);
yield;
console.log(2);
yield;
console.log(3);
yield;
}
var generator = generator_function();
generator.next();
generator.next();
generator.next();
Результат будет точно таким же, но что будет если мы вызовем функцию генератора четыре или более раз, давайте посмотрим:
В результате у нас получилось:
1
2
3
{value: undefined, done: true} или undefined , что означает что значение или сценарий четвертой итерации не определены, потому что она у нас попросту не указана в генераторе.
Теперь давайте что-нибудь скреативим чтобы посмотреть на возможности применения генераторов, рассмотрим такой пример:
function* generator_function(){
yield 'red';
yield 'yellow';
yield 'blue';
yield 'green';
yield 'gray';
yield 'black';
yield 'white';
yield false;
}
var generator = generator_function();
var interval = setInterval(function(){
var value = generator.next().value;
if(value === false){
clearInterval(interval);
return false;
}
console.log('backgroundBody: ',value);
document.querySelector('body').style.background = value;
},1000);
Как видите через каждую секунду у нас вызывается генератор и возвращает значение определенной итерации, в качестве значения возвращается название цвета которое мы подставляем в стиль фона background и выводим значение в консоль. И наконец в самом конце мы завершаем вызов нашего генератора возвращая значение false, которое удовлетворяет условию value === false, и завершает наш таймер setInterval
Так теперь поговорим о методе return(value). Выполнение функции генератора можно завершить в любой момент до того как она вернет нас все значения, вызвав метод return(), который может принимать один необязательный параметр, последнее возвращаемое значение, пример:
function* generator_function(){
console.log(1);
yield;
console.log(2);
yield;
console.log(3);
yield;
}
var generator = generator_function();
generator.next();
generator.next().return();
generator.next();
Результат выполнения:
1
2
Как видите метод return() завершил выполнение на второй итерации нашего генератора, то есть третий вызов функции генератора не был выполнен. Мы можем также в качестве возвращаемого значения генератора принимать , значения другого генератора через ключевое слово, yield*, пример:
function* generator_function(){
console.log(4);
yield;
console.log(5);
yield;
console.log(6);
yield;
}
function* generator_function2(){
console.log(1);
yield;
console.log(2);
yield;
console.log(3);
yield;
yield* generator_function();
}
var generator = generator_function2();
generator.next();
generator.next();
generator.next();
generator.next();
generator.next();
generator.next();
Результат:
1
2
3
4
5
6
До сих пор мы выполняли перебор значений итерируемого объекта с помощью метода next(), что не очень то удобно. В ES6 появился новый цикл for-of предназначений для обхода значений итерируемого объекта, сейчас продемонстрирую его использование:
Берем предыдущий пример, и испоьзуем цикл for-of
function* generator_function(){
console.log(4);
yield;
console.log(5);
yield;
console.log(6);
yield;
}
function* generator_function2(){
console.log(1);
yield;
console.log(2);
yield;
console.log(3);
yield;
yield* generator_function();
}
var generator = generator_function2();
for(var value of generator_function2());
Как видите результат у нас остался код сохранился , если мы допустим записали генератор в таком виде тогда:
function* generator_function2(){
yield 1;
yield 2;
yield 3;
}
var generator = generator_function2();
for(var value of generator_function2()){
console.log(value);
}
Все очень просто, этот цикл кстати можно, использовать для перебора значений массивов, пример:
Можно перебрать одномерный массив так:
var array = [1,2,3];
for(var i in array){
console.log(array[i]);
}
С использованием цикла for-of:
var array = [1,2,3];
for(var i of array){
console.log(i);
}
Большой разницы , как таковой нет, можете перебирать как хотите.
Данная статья подошла к концу, надеюсь я смог донести до вас новую информацию и вы не раз еще ей воспользуетесь. Удачи!