tipos - para terminar las instrucciones en javascript se utiliza
La variable mutable es accesible desde el cierre. ¿Cómo puedo arreglar esto? (4)
Como el único alcance que JavaScript tiene es el alcance de la función , puede simplemente mover el cierre a una función externa, fuera del alcance en el que se encuentre.
Estoy usando Typeahead por twitter. Me encuentro con esta advertencia de Intellij. Esto está causando que "window.location.href" para cada enlace sea el último elemento en mi lista de elementos.
¿Cómo puedo arreglar mi código?
A continuación está mi código:
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);
});
}
}
};
Con la ayuda de @ cdhowie, más código: actualizaré el actualizador y también el href para el clic ()
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))};
En ecmascript 6 tenemos nuevas oportunidades.
La instrucción let declara una variable local de ámbito de bloque, opcionalmente inicializándola en un valor. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
Me gustó el párrafo Closures Inside Loops de Javascript Garden
Explica tres formas de hacerlo.
La forma incorrecta de usar un cierre dentro de un bucle
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
Solución 1 con contenedor anónimo
for(var i = 0; i < 10; i++) {
(function(e) {
setTimeout(function() {
console.log(e);
}, 1000);
})(i);
}
Solución 2 : devolver una función desde un cierre
for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
}
Solución 3 , mi favorita, donde creo que finalmente entendí bind
- yaay! obligar FTW!
for(var i = 0; i < 10; i++) {
setTimeout(console.log.bind(console, i), 1000);
}
Recomiendo Javascript garden , me mostró esto y muchos más caprichos Javascript (y me hizo JS aún más).
ps si tu cerebro no se derritió no has tenido suficiente Javascript ese día.
Necesita anidar dos funciones aquí, creando un nuevo cierre que capture el valor de la variable (en lugar de la variable misma) en el momento en que se crea el cierre . Puede hacer esto usando argumentos para una función externa invocada inmediatamente. Reemplaza esta expresión:
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;
}
Con este:
(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))
Tenga en cuenta que pasamos el target
a la función externa, que se convierte en el argumento inner_target
, capturando efectivamente el valor del target
en el momento en que se llama a la función externa. La función externa devuelve una función interna, que utiliza inner_target
lugar de target
, y inner_target
no cambiará.
(Tenga en cuenta que puede cambiar el nombre de inner_target
al target
y estará bien, se usará el target
más cercano, que sería el parámetro de la función. Sin embargo, tener dos variables con el mismo nombre en un alcance tan estrecho podría ser muy confuso y así Los he nombrado de manera diferente en mi ejemplo para que pueda ver lo que está sucediendo).