2014-12-08 2 views
0

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

Я пытался связать событие с массивом объекта, но каким-то образом прошедшая переменная является последней. После того, как он был повторен.

for (var i = 0; i < map_object.length; i++) { 
    map_object[i].on('mousedown', function(){ 
     var x = i; 
      setEvent(this, x); 
     }); 
}; 

function setEvent(data, i){ 
    console.log(data); 
    var x = i; 
    console.log(x); 
} 

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

Так что, когда он исполнял я всегда получаю этот результат

данные = (некоторые объекты) {ожидаемый результат}

я = 9 {} = непредвиденная map_object.length

I не может понять, связано ли это с тем, что (i) передано как ссылка, или потому, что текущее событие выполняется после завершения итерации.

ВКЛЮЧЕНО функции происходят из Fabricjs

+0

Возможный дубликат http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – SimpleJ

+0

Весь ответ правильный, не стесняйтесь изучать каждый из них. –

ответ

1

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

[].forEach.call(map_object, function(ob, i){ // replace loop with forEach 
    ob.on('mousedown', function(){ 
     var x = i; 
     setEvent(this, x); 
    }); 
}); 

function setEvent(data, i){ 
    console.log(data); 
    var x = i; 
    console.log(x); 
} 

мне, Foreach() просто чувствует себя меньше, «на болты», чем канитель навязанной рамки-менее для петель отсрочки функций ...

EDIT:

если у вас есть JQuery, или что-то вроде этого, есть на самом деле лучший способ сделать это без петля:

$("body").on('mousedown', function(){ 
    var x = map_object.indexOf(this); 
    if(x > -1) setEvent(this, x); 
}); 

function setEvent(data, i){ 
    console.log(data); 
    var x = i; 
    console.log(x); 
} 

Это делает то же самое, но позволяет динамически добавлять/удалять элементы после первоначального запуска, что вы не можете сделать с помощью обработчиков run-once for-loop и отдельных обработчиков событий.

+0

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

0

код выполняется слишком поздно, попробуйте вместо этого:

for (var i = 0; i < map_object.length; i++) { 
    prepareSetEvent(i) 
}; 

function prepareSetEvent(i) { 
    map_object[i].on('mousedown', function(){ 
     var x = i; 
      setEvent(this, x); 
     }); 
} 

function setEvent(data, i){ 
    console.log(data); 
    var x = i; 
    console.log(x); 
} 

Значение i будет скопирован (как примитив) при вызове другой функции. Копия будет использоваться для установки события.

0

К тому времени, когда Событие срабатывает, цикл завершен, поэтому mousedown Событие ищет последнее место i было. Поскольку i имеет глобальный охват, к концу этого цикла он находится в конце цикла. Чтобы этого избежать, вы используете закрытие. То же самое происходит, но так как область входит в самоисполняющееся закрытие i - это то, где вы хотите.

for(var i=0,l=map_object.length; i<l; i++) { 
    (function(i){ 
    map_object[i].on('mousedown', function(){ 
     setEvent(this, i); 
    }); 
    })(i); 
} 

Кстати, в Jquery вы должны использовать $.each() или $('.someclass').each() вместо этого.

+0

Это правильно, но называние 'i' параметра функции приводит к путанице, не могли бы вы отредактировать свой ответ и переименовать его? –

0

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

см https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

for (var i = 0; i < map_object.length; i++) { 
    map_object[i].on('mousedown', setEvent.bind(this, i)); 
}; 
+1

свяжет элемент как _this_ или глобальный как _this_? – dandavis

+0

Хороший вопрос, мне было все равно, это я хотел показать короткое решение. Вы, вероятно, хотите - нужен элемент * как 'this', но в любом случае метод' setEvent' не заботится о значении 'this': P –

+0

для обработчиков событий, это часто необходимо и, к сожалению, bind() нарушает способность использовать _this_ позже в случае, чтобы получить вызывающий элемент. мы по-прежнему можем достичь «старого этого» через аргументы [0] .target в обработчике событий, поэтому он не является разрывом транзакции, но для этого требуется небольшая корректировка вниз по потоку в обработчике событий ... – dandavis

0

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

var x = i; 

x всегда будет иметь такое же значение (размер массива - 1). Вы должны заключить обработчик в функцию и передать параметр переменной в функцию.

for (var i = 0; i < map_object.length; i++) { 
    (function(index) { 
    map_object[i].on('mousedown', function(){ 
      setEvent(this, index); 
     }; 
    })(i); 
}; 

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

+0

oops sorry. неправильные скобки. Нужно было возвышенно видеть, чего я не хватал! – gprasant

Смежные вопросы