I have no idea what is going on, I have spent countless hours debugging my code until I found the weak spot.

Concept

function fnc() {
    var hl = { // hl stands for hyperlink (<a>)
        uid   : ["player.id", "uid"],
        inVal : ["infra.value*", "infrastructure_value"]
    }
    for (key in hl) { .. do the code in block 1 at bottom .. }
}

The code should go through the array (object) of values consisting of id : [text, call] and bind a click(fnc(call)) event to an <a>text</a> with given id. (Clicking the link launches the same function - it is desired.)

The Code

This is the code in short:

fnc = function(sort_by, direction) {
var qswitch = 1;

if (qswitch == 1) {
    key = "uid"; console.log("#"+key); // #uid
    $("#"+key).unbind("click").click( function() { fnc(hl[key][1], direction); });     
    console.log(key); // uid

    key = "inVal"; console.log("#"+key); // #inVal
    $("#"+key).unbind("click").click( function() { fnc(hl[key][1], direction); });    
    console.log(key); // inVal
}

if (qswitch == 2) {    
    $("#uid").unbind("click").click( function() { fnc(hl["uid"][1], direction); });     
    $("#inVal").unbind("click").click( function() { fnc(hl["inVal"][1], direction); }); 
}
}

The problem

You can see two blocks of the same code. The first is supposed to work dynamically as described above, but both links refer to the same function call. (<-this is the error) Binding the events without using a variable works just fine and each link fires it's own function(parameters).

Is it a bug?

..or am I just dumb and overworked?

Install the tampermonkey userscript, visit any site, open console (F12) and watch the output. Whenever you click a link, it writes what function(parameters) it calls. Each of the two links should have different function call. I suggest using this blank site.

theCode.monkey.js

有帮助吗?

解决方案

key = "uid"; console.log("#"+key); // #uid
$("#"+key).unbind("click").click( function() { fnc(hl[key][1], direction); });     
console.log(key); // uid

key = "inVal"; console.log("#"+key); // #inVal
$("#"+key).unbind("click").click( function() { fnc(hl[key][2], direction); });    
console.log(key); // inVal

The problem here is that key is overwritten by the second assignment before it's used in the first callback. Event callbacks are not called at the same time as their defining function and their defining function does not wait for them to be run. The easiest solution would be to use two separate variables, but since it looks like I'm looking at an unrolled loop and your code actually looks like this:

for(var key in hl){
    //compute i
    key = "inVal"; console.log("#"+key); // #inVal
    $("#"+key).unbind("click").click( function() { fnc(hl[key][i], direction); });    
    console.log(key); // inVal
}

(if var is missing, you should add it - undeclared variables reside in the global scope. You don't want them there. In strict mode, they fail completely) (not sure where i comes from, but let's assume it's generated in each loop before what is seen) you can use an immediately invoked function expression (IIFE) to capture the value into a new variable in a new scope (remember, javascript uses function scopes):

for(var key in hl){
    // compute `i`
    (function(key, i){
        key = "inVal"; console.log("#"+key); // #inVal
        $("#"+key).unbind("click").click( function() { fnc(hl[key][i], direction); });    
        console.log(key); // inVal
    })(key,i)
}

now key and i inside the loop refer to the IIFE arguments, not to the constantly changing variable variables declared outside the loop.

Also note that: if previous values of i are not used to generate new ones, then the computation of i can be moved into the function body. If they are used - please note that the order of object keys is not guaranteed.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top