Jump to content
  • 0

Определить уровень тупости


Mixail.09
 Share

Question

Здравствуйте.

Помогите разобраться вот с такой проблемой.

Начал учить JS на сайте learn.javascript.ru и все было нормально (даже хорошо), осваивал материал, решал задачки после тем. После пройденной темы задачи решались довольно легко (ну было конечно пару трудных моментов) и тут "замыкания"!!! (в голове бл...ин замыкания от них начались). И начинался какой то АД АДОВЫЙ. Читаю материал, все норм, все понятно, смотрю задачи и .... просто ступор, смотрю решение и даже видя решение ни чего не могу понять!

И так уже неделю.

Сразу возник закономерный вопрос, может я просто неисправимо ТУП!!! Просто какое то отчаяние.
Что вы думаете про данный курс? Может что полегче, так сказать для средних умов посоветуете для начала?

Ниже пример задачи.

 

 

Следующий код создает массив функций-стрелков shooters. По замыслу, каждый стрелок должен выводить свой номер:

 
 
function makeArmy() {

var shooters = [];

for (var i = 0; i < 10; i++) {
var shooter = function() { // функция-стрелок
alert( i ); // выводит свой номер
};
shooters.push(shooter);
}

return shooters;
}

var army = makeArmy();

army[0](); // стрелок выводит 10, а должен 0
army[5](); // стрелок выводит 10...
// .. все стрелки выводят 10 вместо 0,1,2...9
 

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

Link to comment
Share on other sites

18 answers to this question

Recommended Posts

  • 0

example

for (var i = 0; i < 10; i++) {    var shooter = function() { // функция-стрелок    alert( i ); // выводит свой номер};...

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

function makeArmy() {var i;var shooters = [];for (i = 0; i < 10; i++) {    var shooter = function() {    alert( i );};...

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

Link to comment
Share on other sites

  • 0

Mixail.09, имхо, нет, вы не тупой. Тема "Замыкания" у многих вызывает ступор и трудности. Просто вам нужен человек, который объяснит вам эту тему подробно, чтобы вы могли въехать) и тогда всё будет хорошо, дело сдвинется с мёртвой точки:)

  • Like 1
Link to comment
Share on other sites

  • 0

Замыкания - это очень просто. Посмотрите на такую функцию:

function myFunction(a, B) {  var sum = a + b;    return sum;}
На самом деле внутри у неё, скрытно от вас, создался невидимый объект, в котором хранится переменная sum. Т.е. для интерпретатора (в нашем случае интерпретатор - это браузер) функция выглядит вот так:

function myFunction(a, B) {  invisibleObject.sum = a + b;  return invisibleObject.sum;}
После того как функция отработала вступает в дело "сборщик мусора", который освобождает память на компе, которую занял этот самый invisibleObject, чтобы у вас браузер и вообще винда не тормозили. Так вот, замыкание - это когда сборщик мусора этот самый invisibleObject не удаляет. Классический пример:

var counter;function myFunction() {  var start = 0;  counter = function() {    return start++;  };}myFunction(); // вызываем функцию, чтобы инициализировать переменную counter// далее юзаем уже countercounter(); // 0counter(); // 1counter(); // 2 и т.д.
Браузер не дурак и видит, что переменная start может ещё понадобится в будущем, так как она используется внутри counter, поэтому он этот самый infisibleObject после того как мы вызвали myFunction не удаляет. Это и называется замыкание.

 

tl;dr

Замыкание - это когда невидимый объект, в котором функция хранит локальные переменные не удаляется после того как функция отработает.

P.S. Кстати, этим "невидимым объектом" был Альберт Эйнштейн LexicalEnvironment.

  • Like 5
Link to comment
Share on other sites

  • 0

Спасибо за ответы.

Сейчас снова пытался разобраться, и вот в чем главное непонимание.

Пример:

 

function inBetween( a, b ) {

     return function (x){
          if (a<=x && b>=x){
               return true;
               }
          return false;
     }
};
 
function filter (array, filt) {
     var newArr = [];
     for (i=0; i<array.length; i++){
          var x = array;
          if (filt(x)){
               newArr.push(x)
          }
     }
     return newArr;
};
 
var arr = [1, 2, 3, 4, 5, 6, 7];
 
alert(filter(arr,inBetween(3, 6)));
 
Вот так это работает:    http://codepen.io/anon/pen/WwvqPw
 
Вот в чем самый главный вопрос (ни как в голове не сформулируется понимание этого):
мы по идее передаем функции inBetween два аргумента, но filt(x) здесь то один аргумент? И я бы еще понял еслиб там просто круглые скобки были, типа просто выполнить функцию с аргументами заданными в дальнейшем, но откуда X не ясно?
Edited by Mixail.09
Link to comment
Share on other sites

  • 0

ну)  
alert(filter(arr,inBetween(3, 6)));
здесь второй аргумент у тебя будет не функция 
inBetween, а её результат.  который ты и будешь в цикле вызывать

     function (x){          if (3<=x && 6>=x){               return true;          }          return false;     }

просто запомните, когда вы строите код - стройте его так, чтобы хотя бы вы его понимали(на первых этапах =).  не понимаете про замыкания, ну не используйте их. Хотя в некотрых случаях без них никак. 
потом со временем понимание придет.  А то так и будете каждый раз смотреть в свой код и думать - чё это, кто это писал... =)

Link to comment
Share on other sites

  • 0

но откуда X не ясно?

 

 

 

 

Всё очень просто, смотри.  Функция filter принимает массив чисел и функцию inBetween с диапазоном от и до . Далее она берёт каждое число в массиве и запускает inBetween в который передаёт это число. Это и есть X !

 var x = array

 

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

Link to comment
Share on other sites

  • 0

Ребята, спасибо! Кажется начинаю понимать.

То есть получается по сути вот это выражение 

function filter (array, filt) {
     var newArr = [];
     for (i=0; i<array.length; i++){
          var x = array;
          if (filt(x)){
               newArr.push(x)
          }
     }
     return newArr;
};
при выполнении будет выглядеть так:
function filter (array, filt) {
     var newArr = [];
     for (i=0; i<array.length; i++){
          var x = array;
          if (function (x){
                    if (a<=x && b>=x){
                    return true;
                     }
                     return false;}){
               newArr.push(x)
          }
     }
     return newArr;
};

Ну соответственно вместо синей ф-ции вернется true / false

Link to comment
Share on other sites

  • 0

Еще вопрос по теме, помогите далее разобраться:  http://codepen.io/anon/pen/zqvJMM

 

function makeBuffer() {
     var text = '';
     function buffer(piece) {
          if (arguments.length == 0) { // вызов без аргументов
                    return text;
               }
               text += piece;
          };
          buffer.clear = function() {
          text = "";
     }
     return buffer;
};

var buffer = makeBuffer();


buffer("Тест");
buffer(" тебя не съест ");
alert( buffer() ); // Тест тебя не съест

buffer.clear();

alert( buffer() ); // ""

 

Вот это  buffer("Тест"); вызывают функцию оболочку (makeBuffer) и передает вложенной в нее функции какое то значение т.к. var buffer = makeBuffer() ,  Затем buffer(" тебя не съест ");  делает тоже самое еще раз. Тут как я понимаю buffer - это не имя вложенной ф-ции, а имя переменной. Отсюда вопрос - если бы было две вложенные ф-ции то в какую из них бы тогда передался этот аргумент, ведь не указано же ни где имя вложенной ф-ции, вот так например было бы все четко и ясно (по крайней мере для новичков как я) buffer.buffer(arg), ну или так makeBuffer.buffer(arg) ?

alert( buffer() ) - с этим вроде все ясно.

buffer.clear() - вот тут пошла путаница. Здесь buffer - это как я понял опять таки имя переменной (var buffer = makeBuffer()).  И опять вот такая запись была бы понятной  buffer.buffer.clear() или makeBuffer.bufer.clear(). Опять же если есть две вложенный ф-ции и у каждой есть метод clear() то при такой записи buffer.clear() получается оба сработают?

 

 

Link to comment
Share on other sites

  • 0

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

buffer - функция. Вызывает она (внезапно!) функцию buffer. 

 Отключай фантазию.

  • Like 1
Link to comment
Share on other sites

  • 0

В переменную buffer записывается возвращаемое функцией makeBuffer значение. Возвращается замыкание.

Дальше работаем с ней, как с обычной функцией.

 

упс...

Не правильно понял предыдущие объяснения.  Я то подумал что вот этим var buffer = makeBuffer(); присваивается переменной buffer все что внутри makeBufer(), а оказывается только то что return.

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

Сейчас в свете последних ответов попробую еще раз прозреть, хотя уже не в чем не уверен)

Link to comment
Share on other sites

  • 0

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

 

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

http://kharchuk.ru/JavaScript.pdf

Страница 156.

 

https://www.dropbox.com/s/ahgcimlrisuik95/Screenshot%202016-03-11%2005.29.58.png?dl=0

  • Like 1
Link to comment
Share on other sites

  • 0

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

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

Function func( ) {

Var x = 0;

Return function f () {

Return x++;

}

}

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

Var a = func() - то есть вызвали внешнюю ф- цию и присвоили ее return переменной a.

То есть переменная a сейчас равна вложенной ф-ции function f() { return x++} . И теперь весь смысл замыкания в том что переменная x++ ссылается на обьявленную переменную из внешней ф-ции которая как писал выше по идее должна уничтожиться, но в этом и есть замыкания что если такая ссылка на несуществующую есть то она не уничтожается, а сохраняется в невидимом обьекте и у внутренней функции f остается к ней доступ.

P.s наверное лютый баян написал, но думаю лишним не будет)

Link to comment
Share on other sites

  • 0

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

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

Function func( ) {

Var x = 0;

Return function f () {

Return x++;

}

}

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

Var a = func() - то есть вызвали внешнюю ф- цию и присвоили ее return переменной a.

То есть переменная a сейчас равна вложенной ф-ции function f() { return x++} . И теперь весь смысл замыкания в том что переменная x++ ссылается на обьявленную переменную из внешней ф-ции которая как писал выше по идее должна уничтожиться, но в этом и есть замыкания что если такая ссылка на несуществующую есть то она не уничтожается, а сохраняется в невидимом обьекте и у внутренней функции f остается к ней доступ.

P.s наверное лютый баян написал, но думаю лишним не будет)

 

Все правильно написал. Все так)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. See more about our Guidelines and Privacy Policy