我正在通过推特使用Typeahead。我正在接受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的帮助下,还有一些代码: 我将更新更新程序以及click()
的hrefupdater: (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))};
答案 0 :(得分:138)
它解释了三种方法。
在循环中使用闭包的错误方法
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 :(得分:61)
你需要在这里嵌套两个函数,创建一个新的闭包,它在创建闭包时捕获变量的值(而不是变量本身) 。您可以使用立即调用的外部函数的参数来执行此操作。替换此表达式:
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
的值。 outer函数返回一个内部函数,它使用inner_target
而不是target
,inner_target
不会改变。
(请注意,您可以将inner_target
重命名为target
,然后您就可以了 - 将使用最接近的target
,这将是函数参数。但是,有两个变量在如此狭窄的范围内使用相同的名称可能会非常混乱,因此我在示例中对它们进行了不同的命名,以便您可以看到正在发生的事情。)
答案 2 :(得分:10)
在ecmascript 6中,我们有了新的机会。
let 语句声明一个块作用域局部变量,可选择将其初始化为一个值。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
答案 3 :(得分:1)
由于JavaScript唯一的范围是 function 范围,因此您只需将闭包移动到您所在范围之外的外部函数。
答案 4 :(得分:0)
只是为了澄清@BogdanRuzhitskiy的答案(因为我不知道如何在注释中添加代码),使用let的想法是在for块内创建一个局部变量:
for(var i = 0; i < 10; i++) {
let captureI = i;
setTimeout(function() {
console.log(captureI);
}, 1000);
}
这几乎可以在除IE11之外的所有现代浏览器中使用。