为什么我的所有JavaScript按钮都返回字母Z? [英] Why all my JavaScript buttons return letter Z?

查看:65
本文介绍了为什么我的所有JavaScript按钮都返回字母Z?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JavaScript进行Hangman自学习



我添加了字母按钮,它们显示正确但点击时所有按钮返回Z,为什么?



I am making Hangman in JavaScript for self-learning

I added alphabet buttons and they appear correctly but all buttons when clicked return Z, why?

function set_controls(){
    text_tries=document.getElementById('text_tries');
    var divalpha = document.getElementById('alpha_buttons');
    var letters = alphabet.split("");
    for(var i=0;i<alphabet.length;i++){
        if(i%9==0){
            var br = document.createElement('br');
            divalpha.appendChild(br);
        }
        var b = document.createElement('button');
        var ch = letters[i];
        var str = ch.toString();
        var b_id=str+'btn';
        debug('add button id=' + b_id);
        b.setAttribute('id',b_id);
        b.innerHTML=str;
        b.style.backgroundColor="yellow";
        b.style.color="black";
        b.style.fontWeight="bold";
        divalpha.appendChild(b);
        b.onclick=function(){
            submit_letter(b_id)
        };

    }
}

function init_hangman(){
    set_controls();
    hangman_contest.fx.new_game();
}

function submit_letter(btn_id){
    debug('clicked button id=' + btn_id);
    var letter=document.getElementById(btn_id).innerHTML;
    debug(letter);
    hangman_contest.fx.add_letter(letter);
    var tries=document.getElementById('text_tries');
    tries.value=hangman_contest.usedletters.join("");
}









似乎创建了点击事件对于按钮Z指向所有按钮???





It seems the click event created for button Z is pointing to all buttons???

推荐答案

该错误太简单了:您使用 b_id submit_letter(b_id)中。这是所有按钮共享的一个对象。它的价值是什么?在最后一次迭代时分配给该变量的值'Z'。一个有趣的问题是这个问题:这个值如何通过局部变量(即堆栈上的变量,通常)可以访问事件处理程序对象。这个问题根本不是微不足道的:这是闭包的影响。学习编程这一重要的高级方面非常重要: http://en.wikipedia.org/wiki/Closure_( computer_programming) [ ^ ]。



对闭包的理解并不那么容易。如果本文不清楚,请提出问题;我会解释一下。



这是你如何理解正在发生的事情。考虑执行顺序。在循环中,您只创建函数对象并将它们分配给属性 onclick 。在完成循环之前,您永远不会调用这些函数。当用户点击后调用事件时,这些函数会被调用很多。当执行呼叫时,使用 b_id 。通常,此对象甚至不会作为离开堆栈帧后的局部变量存在。但是闭包的效果(由于在处理程序中使用变量)保留了这个变量,所以它可以在处理程序中使用。它的价值是什么?在循环执行的最后一次迭代中分配给它们的值。 Z.



还有一些问题:

你不需要拆分字母。坏了,你没有显示它的定义,但我几乎可以肯定它就像字符串ABCD .... F。您可以直接访问每个字符,如 alphabet [index] 。此外,连接btn是一个非常糟糕的主意。属性 id 值最好是A,B等。此外,您可以指定一些其他属性并使用它,例如名称,它将放宽唯一性要求。但是你的主要问题是:你从不使用分配的属性值。



那么,什么是正确的解决方案?非常简单:您需要使用按钮单击处理程序的参数。让我们忘记我的建议,将任何属性值分配给字母表。您可以简单地将按钮文本( innerHTML )分配给这些字母或带有一些标记的字母。为简单起见,我们假设只有字母(否则你总是可以从 innerHTML 字符串中提取该字母)。那么你的处理程序可能如下所示:

The bug is way too trivial: you are using b_id in submit_letter(b_id). This is one object shared by all the buttons. What is its value? The values assigned to this variable at the last iteration, 'Z'. One interesting question is this one: how this value, accessible via a local variable (that is, a variable on stack, normally) can get to the event handler object. This question is not trivial at all: this is the effect of closure. It is very important to learn this important advanced aspect of programming: http://en.wikipedia.org/wiki/Closure_(computer_programming)[^].

Understanding of closures in not so easy. If something is not clear in this article, please ask a question; I'll explain.

Here is how you can understand what's going on. Consider order of execution. In your loop, you only create function objects and assign them to the property onclick. You never call those functions before you complete the loop. Those functions are called a lot later, when the event is invoked as a result of the user's click. And when the call is performed b_id is used. Normally, this object would not even exist, as a local variables after leaving the stack frame. But the effect of closure (due to the use of the variable inside the handler) preserves this variable, so it could be used in the handler. And what is it's value? The value assigned back them, at the last iteration of the loop execution. Z.

Some more problems:
You don't need to split alphabet. To bad you did not show its definition, but I'm almost sure it is something like the string "ABCD....F". You can access each character directly, as alphabet[index]. Also, it's quite a bad idea to concatenate "btn". The attribute id value could better be "A", "B", etc. Moreover, you could assign some other attribute and use it, for example name, it would relax the uniqueness requirements. But your main problem is: you never use the attribute values assigned.

So, what would be the correct solution? Pretty simple: you need to use the argument of the button click handler. Let's forget my advice to assign any attribute values to the letters of alphabet. You could simply assign button texts (innerHTML) to those letters, or letters with some markup. Let's assume there are just letters, for simplicity (otherwise you can always extract that letter from innerHTML string). Then your handler may look like this:
b.onclick = function(eventInstance) {
   submit_letter(eventInstance.target.innerHTML)
}



请注意 eventInstance.target 是参考到您调用该事件的按钮。如果你想使用一些属性,你可以从这个对象中提取属性值。



请参阅:

https://developer.mozilla.org/en-US/docs/Web/API/Event [< a href =https://developer.mozilla.org/en-US/docs/Web/API/Eventtarget =_ blanktitle =New Window> ^ ],

https://developer.mozilla.org/en-US/docs/Web / API /事件/目标 [ ^ ]。



-SA


Note that eventInstance.target is the reference to your button which invoked the event. If you want to use some attributes, you can extract the attribute value from this object.

Please see:
https://developer.mozilla.org/en-US/docs/Web/API/Event[^],
https://developer.mozilla.org/en-US/docs/Web/API/Event/target[^].

—SA


哇!即使主要问题在解决方案1中得到了充分的回答,经过一番思考,我发明了一种非常不同的方法解决这些问题,更加可靠和灵活,因为你不必在按钮之间创建额外的耦合属性,HTML或任何其他属性,因此您可以直接从处理程序中提取字母。



同时,它更加微妙,理解需要更深入地理解JavaScript的。您应该了解函数对象可以用作其他对象,因此您可以为它们添加任何属性。所以,这就是你在循环中可以做的事情:

Wow! Even though the main question is fully answered in Solution 1, after some thinking, I invented a very different approach to such problems, more reliable and flexible, because you don't have to create extra coupling between buttons attributes, HTML or any other properties, so you can extract the letter directly from the handler.

At the same time, it's more subtle and the understanding requires deeper understanding of JavaScript. You should understand that functions objects can be used as other objects, so you can add any properties for them. So, this is what you can do inside your loop:
var b_id = //...
var functionObject = function() {
    submit_letter(arguments.callee.letter);
}
functionObject.letter = "A";
b.onclick = functionObject;



如您所见,您提交的信件与按钮对象完全分离。按钮对象和功能对象之间只有一个点或绑定,属性 onclick



此解决方案但有一个大问题:在严格模式中不允许使用 callee

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode [ ^ ],

https://developer.mozilla.org / en-US / docs / Web / JavaScript / Reference / Functions / arguments / callee [ ^ ]。



我想说谢谢你:你宁愿天真的问题激发灵感有趣的想法,与深层次的事情有关。



-SA


As you can see, your letter submitted is totally decoupled from the button objects. There is only one point or binding between the button objects and function objects, the property onclick.

This solution has one big problem though: using callee is not allowed in strict mode:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode[^],
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee[^].

I want to say thank you: your rather naive question inspires interesting thoughts and is related to deeply fundamental things.

—SA


这篇关于为什么我的所有JavaScript按钮都返回字母Z?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆