可变variables可以从闭包访问。 我怎样才能解决这个问题?
我通过twitter使用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()
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))};
你需要在这里嵌套两个函数,创build一个新的闭包,在创build闭包的时候捕获variables的值(而不是variables本身)。 您可以使用参数立即调用外部函数。 replace这个expression式:
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
,这将是函数参数。但是,如果在如此紧密的范围内有两个同名的variables,可能会非常混乱在我的例子中,我用不同的名字来命名它们,这样你就可以看到发生了什么。)
我喜欢从Javascript花园 里面的循环 闭环
它解释了三种做法。
在循环中使用闭包的错误方法
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 1000); }
解决scheme1与匿名包装
for(var i = 0; i < 10; i++) { (function(e) { setTimeout(function() { console.log(e); }, 1000); })(i); }
解决scheme2 – 从闭包返回一个函数
for(var i = 0; i < 10; i++) { setTimeout((function(e) { return function() { console.log(e); } })(i), 1000) }
解决scheme3 ,我最喜欢的,我想我终于明白bind
– 你好! 绑定FTW!
for(var i = 0; i < 10; i++) { setTimeout(console.log.bind(console, i), 1000); }
我强烈推荐Javascript花园 – 它向我展示了这个以及更多的Javascript怪癖(使我更像JS)。
如果你的大脑没有融化,那么你那天没有足够的Javascript。
在ecmascript 6中,我们有了新的机会。
let语句声明一个块作用域局部variables,可以将其初始化为一个值。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
由于JavaScript所具有的唯一范围是函数范围,因此只需将闭包移动到外部函数,而不在范围之内。