2013-05-23 1 views
61

Я использую Typeahead по twitter. Я сталкиваюсь с этим предупреждением от Intellij. Это вызывает «window.location.href» для каждой ссылки как последний элемент в моем списке элементов.Переключаемая переменная доступна из закрытия. Как я могу это исправить?

Как я могу исправить свой код?

Ниже мой код:

AutoSuggest.prototype.config = function() { 
    var me = this; 
    var comp, options; 
    var gotoUrl = "/{0}/{1}"; 
    var imgurl = '<img src="/icon/{0}.gif"/>'; 
    var target; 

    for (var i = 0; i < me.targets.length; i++) { 
     target = me.targets[i]; 
     if ($("#" + target.inputId).length != 0) { 
      options = { 
       source: function (query, process) { // where to get the data 
        process(me.results); 
       }, 

       // set max results to display 
       items: 10, 

       matcher: function (item) { // how to make sure the result select is correct/matching 
        // we check the query against the ticker then the company name 
        comp = me.map[item]; 
        var symbol = comp.s.toLowerCase(); 
        return (this.query.trim().toLowerCase() == symbol.substring(0, 1) || 
         comp.c.toLowerCase().indexOf(this.query.trim().toLowerCase()) != -1); 
       }, 

       highlighter: function (item) { // how to show the data 
        comp = me.map[item]; 
        if (typeof comp === 'undefined') { 
         return "<span>No Match Found.</span>"; 
        } 

        if (comp.t == 0) { 
         imgurl = comp.v; 
        } else if (comp.t == -1) { 
         imgurl = me.format(imgurl, "empty"); 
        } else { 
         imgurl = me.format(imgurl, comp.t); 
        } 

        return "\n<span id='compVenue'>" + imgurl + "</span>" + 
         "\n<span id='compSymbol'><b>" + comp.s + "</b></span>" + 
         "\n<span id='compName'>" + comp.c + "</span>"; 
       }, 

       sorter: function (items) { // sort our results 
        if (items.length == 0) { 
         items.push(Object()); 
        } 

        return items; 
       }, 
// the problem starts here when i start using target inside the functions 
       updater: function (item) { // what to do when item is selected 
        comp = me.map[item]; 
        if (typeof comp === 'undefined') { 
         return this.query; 
        } 

        window.location.href = me.format(gotoUrl, comp.s, target.destination); 

        return item; 
       } 
      }; 

      $("#" + target.inputId).typeahead(options); 

      // lastly, set up the functions for the buttons 
      $("#" + target.buttonId).click(function() { 
       window.location.href = me.format(gotoUrl, $("#" + target.inputId).val(), target.destination); 
      }); 
     } 
    } 
}; 

С помощью @ cdhowie в, некоторый код: я буду обновлять программу обновления и также HREF для мыши()

updater: (function (inner_target) { // what to do when item is selected 
    return function (item) { 
     comp = me.map[item]; 
     if (typeof comp === 'undefined') { 
      return this.query; 
     } 

     window.location.href = me.format(gotoUrl, comp.s, inner_target.destination); 
     return item; 
}}(target))}; 
+1

Yao (замечание общего порядка, не связанные с вопрос): 'matcher' не включает в себя тот же' if (typeof comp === 'undefined') {...} 'тест безопасности, включенный в' highlighter' и 'updater'. Быстро взглянув на код, похоже, что это может быть недосмотр. –

+0

@ Beetroot-Beetroot ooohhhhhh хороший улов !!! Спасибо!!! удивительно, что я не получил никаких ошибок, когда нет совпадений =/ – iCodeLikeImDrunk

+1

Яо, похоже, что у вас хорошая погрешность в других местах вашего кода, но «пояс + брекеты» никогда никому не повредит. –

ответ

56

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

function (item) { // what to do when item is selected 
    comp = me.map[item]; 
    if (typeof comp === 'undefined') { 
     return this.query; 
    } 

    window.location.href = me.format(gotoUrl, comp.s, target.destination); 

    return item; 
} 

С этим:

(function (inner_target) { 
    return function (item) { // what to do when item is selected 
     comp = me.map[item]; 
     if (typeof comp === 'undefined') { 
      return this.query; 
     } 

     window.location.href = me.format(gotoUrl, comp.s, inner_target.destination); 

     return item; 
    } 
}(target)) 

Обратите внимание, что мы перейдем target во внешнюю функцию, которая становится аргументом inner_target, эффективно захватывая значение target в данный момент внешняя функция называется. Внешняя функция возвращает внутреннюю функцию, которая использует inner_target вместо target, а inner_target не изменится.

(Обратите внимание, что вы можете переименовать inner_target в target, и вы будете в порядке - ближайший target будет использоваться, который был бы параметр функции Однако, имея две переменные с тем же именем, в таком напряженном объеме может быть. очень запутанной и поэтому я назвал их по-разному в моем примере, так что вы можете увидеть, что происходит.)

+0

как насчет второй части? где я устанавливаю href для кнопки? этот способ делать вещи кажется мне сверхъестественным =/ – iCodeLikeImDrunk

+2

@yaojiang Применить ту же технику. Если вам нужна помощь, дайте мне знать, и мы можем переехать в чат. Но сначала попробуйте понять, что происходит в моем примере, и попытайтесь сделать это сами. (Концепция будет лучше, если вы сделаете это сами!) – cdhowie

+0

Я скоро обновлю свой код. – iCodeLikeImDrunk

124

мне понравился пункт Колпачки Внутри Loops от Javascript Garden

Это объясняет три способа сделать это ,

неправильный способ использования закрытия внутри цикла

for(var i = 0; i < 10; i++) { 
    setTimeout(function() { 
     console.log(i); 
    }, 1000); 
} 

Решения 1 с анонимной оберткой

for(var i = 0; i < 10; i++) { 
    (function(e) { 
     setTimeout(function() { 
      console.log(e); 
     }, 1000); 
    })(i); 
} 

Решение 2 - возвращение функции от закрытия

for(var i = 0; i < 10; i++) { 
    setTimeout((function(e) { 
     return function() { 
      console.log(e); 
     } 
    })(i), 1000) 
} 

Решение 3, мой любимый, где я думаю, я наконец понял bind - yaay! свяжите FTW!

for(var i = 0; i < 10; i++) { 
    setTimeout(console.log.bind(console, i), 1000); 
} 

Я настоятельно рекомендую Javascript garden - он показал мне это и много больше Javascript причуды (и сделал мне как JS даже больше).

p.s. если ваш мозг не растает, в этот день вам не хватило Javascript.

1

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