Как заставить этот код работать?
Код дает мне: A B C
Когда я нажимаю на ABC, он всегда показывает последнюю "водку". Я хочу, чтобы "Мартин" (для A), "Линдсей" (для B), "Водка" (для C)
Пожалуйста, помогите мне на моем примере.
myArray = [
{
letter: "A",
brand: "martin"
},
{
letter: "B",
brand: "lindsay"
},
{
letter: "C",
brand: "vodka"
}
];
var list = '';
for (var i = 0; i < myArray.length; i++) {
list += "<br>" + myArray[i].letter;
new_info = myArray[i].link;
(function(new_info) {
$(this).click(function(){ //this - refers to A or B or C
$('#box2').text(new_info);
});
}).call(this, myArray[i])
}
$('#box1').append(list);
1 ответ
Редактировать:
Я сказал, что не собираюсь писать ваш код для вас... ну, я сделал: эта скрипка делает именно то, что вы ищете. Я решил проблему с контекстом (this
), вопросы закрытия и подразумеваемые глобалы. Надо еще много работы, но скрипка показывает, что все говорили: $(this)
не имеет, не может и никогда не будет указывать на строковую константу, такую как"A", or "B"
,
Извините, что говорю это, но ваш код полон проблем, но я рассмотрю конкретную проблему, о которой вы здесь спрашиваете.
Внутри цикла вы назначаете обработчик кликов, который в основном выглядит следующим образом:
function()
{
$('#box2').text(new_info);
}
куда new_info
переменная, которая объявлена в более высокой области видимости Все идет нормально. Проблема в том, что создаваемый объект функции не имеет собственной копии какого-либо значения этой переменной (new_info
) произошло, когда эта функция была создана. Вместо этого функция ссылается на эту переменную. Поэтому, когда любая из этих функций вызывается $('#box2').text(new_info)
будет решен в $('#box2').text("whatever value new_info holds when function is called")
не $('#box2').text("whatever value new_info was holding when function was created")
, Вы можете предоставить каждому обратному вызову доступ к копии, просто добавив в свой код вторую функцию:
$(this).click((function(currentNewInfo)
{
return function()
{
$('#box2').text(currentNewInfo);
}
}(new_info)));
Здесь я создаю функцию, которая принимает аргумент и вызывает его немедленно. я пас new_info
в качестве аргумента, поэтому значение currentNewInfo
будет что new_info
держит в то время (ака копия)
Вызванная мною функция (IIFE - или выражение немедленно вызванной функции) возвращает фактический обратный вызов. В этом обратном вызове я не упоминаю new_info
, но аргумент IIFE: currentNewInfo
,
Поскольку каждая функция имеет свою область видимости, эта переменная заключена (отсюда и закрытие имени) и не может быть доступна или изменена извне. Единственное, что еще может получить доступ к currentNewInfo
Переменная - это функция, возвращаемая IIFE.
Возможно, вас беспокоит конфликт имен (каждый созданный вами обратный вызов использует ссылки currentNewInfo
), но это не так: каждый обратный вызов был создан отдельной функцией и, следовательно, имеет доступ к другой области. Невозможно иметь конфликт имен между областями, которые не имеют доступа друг к другу... Просто чтобы сделать вещи действительно простыми для понимания:
Where /\ and /\
|| ||
is return function() is scope of IIFE
Таким образом, замыкания имеют доступ к области действия функции после ее возврата. Эта область имеет приоритет при разрешении выражения в значение. Чтобы лучше это понять, вот похожая диаграмма, показывающая, как JS разрешает выражения:
Где каждая розовая "запись внешней среды" - это область действия функции (область закрытия функции, которая уже вернулась, или функция, которая вызывается в данный момент). Последнее окружение будет либо глобальным объектом, либо нулевым (в строгом режиме). Это все, что нужно сделать.
Честно говоря, затворы сложно сначала обдумать, но как только вы поймете, что я пытался объяснить здесь, это будет очень весело.
Пройдя по этой ссылке, я могу перейти к описанию вариантов использования и преимуществ, а также способов работы вложенных замыканий, но в итоге я бы написал книгу. Ссылка, которую я разместил, отлично объясняет, как работают замыкания, используя довольно глупые рисунки. Это может показаться детским, но на самом деле они мне очень помогли, когда я пытался понять концепцию лямбда-функций, замыканий и областей действия вне вызова функции. Диаграммы выше взяты со страницы, на которую я ссылаюсь, которая объясняет концепции немного более подробно, но я все еще думаю, что простые, грубые рисунки довольно понятны.
Другие вопросы:
Как кто-то указал: "Чего вы ожидаете? this
для ссылки ". Глядя на фрагмент, this
будет просто ссылаться на глобальный объект (window
), прикрепляя такой же / похожий обработчик событий к window
просто не имеет смысла, если вы спросите меня.
Глобальные переменные являются злом, аглобальные переменные - тем более. Я не вижу new_info
ни myArray
быть объявленным где угодно Способ, с помощью которого JS разрешает выражения, весьма неудачен и откатывается на создание глобальных переменных без какого-либо взгляда:
var bar = 666;//global, always evil
function createGlobal()
{
var local = 2;
foo = bar * local;
}
createGlobal();
Давайте посмотрим на foo
:
JS is in createGlobal scope: var local is declared, and assigned 2.
foo is used, and assigned bar*local
|| || \\=>found in current scope, resolves to 2
|| ||
|| \\=>found in global scope, resolves to 666
||
||
||=> JS looks for foo declaration in function scope first, not found
||
||=> moves up 1 scope (either higher function, or global scope)
||
\\=>Global scope, foo not found, create foo globally! - hence, implied global
\\
\\=>foo can now be resolved to global variable, value undefined
Чрезмерные запросы DOM: все ваши обратные вызовы обработчика событий выглядят так:
$('#box2').text(new_info);
Это ($('#box2')
) на самом деле так же, как написание document.getElementById('#box2')
, Который практически английский. Думайте об этом так: каждый раз, когда клиент нажимает на $(this)
- что бы это ни было, вы обращаетесь к DOM и сканируете его на предмет с заданным идентификатором. Почему бы не сделать это один раз и использовать ссылку, хранящуюся в памяти, чтобы изменить текст. Это сохраняет бесчисленные запросы DOM. Вы можете использовать переменную или (в свете того, что я объяснил о замыканиях) замыкание:
var list = (function(box2, list, i)
{//list & i are arguments, so local to scope, too
for (i = 0; i < myArray.length; i++)
{
list += "<br>" + myArray[i].letter;//<-- don't know why you use this
//new_info = myArray[i].link; no need for this var
$(this).click((function(new_info)
{//new_info is closure var now
return function ()
{//box2 references DOM element, is kept in memory to reduce DOM querying
box2.text(link);
};
}(myArray[i].link));//instead of new_info, just pass value here
}
return list;//return string, assign to outer variable
}($('#box2'), ''));//query dom here, pass reference as argument