3

Window加载时,DD内部的每个元素Quote_App都应该onCLick附加一个触发函数的事件Lorem,但是,Lorem返回语句中最后一个元素的nodeName和,而不是触发函数的元素的和。我想返回触发该函数的元素的and 。IdForLoremnodeNameId

function Lorem(Control){

/*     this.Control=Control; */
    this.Amet=function(){
        return Control.nodeName+"\n"+Control.id;
    };

};

function Event(Mode,Function,Event,Element,Capture_or_Bubble){
    if(Mode.toLowerCase()!="remove"){
        if(Element.addEventListener){
            if(!Capture_or_Bubble){
                Capture_or_Bubble=false;
            }else{
                if(Capture_or_Bubble.toLowerCase()!="true"){
                    Capture_or_Bubble=false;
                }else{
                    Capture_or_Bubble=true;
                };
            };
            Element.addEventListener(Event,Function,Capture_or_Bubble);
        }else{
            Element.attachEvent("on"+Event,Function);
        };
    };
};

function Controls(){
    var Controls=document.getElementById("Quote_App").getElementsByTagName("dd");
    for(var i=0;i<Controls.length;i++){

        var Control=Controls[i];

        Event("add",function(){

            var lorem=new Lorem(Control);
            lorem.Control=Control;
            alert(lorem.Amet());

        },"click",Controls[i]);

    };
};

Event("add",Controls,"load",window);

目前,您单击任何DD元素Lorem总是返回最后一个元素的nodeNameand 。IdDD

Lorem应该返回触发的( ) 的nodeNameand 。IdControlControl[i]Lorem

我该如何去做呢?

谢谢!

4

3 回答 3

5

您需要在循环内有一个闭包,您将在其中附加事件处理程序以捕获i每个循环迭代中的值。

  for(var i=0;i<Controls.length;i++) {   
    (function() {
        var Control=Controls[i];

        Event("add",function(){

            var lorem=new Lorem(Control);
            lorem.Control=Control;
            alert(lorem.Amet());

         },"click",Controls[i]);
    })();
  };

在这里,我使用 JavaScript 的好朋友自调用匿名函数在上面创建了一个闭包。

需要闭包的原因是没有它,i任何事件处理函数执行时的值将是i最后一次循环迭代中的值,而不是我们想要的值。我们希望在每次循环迭代中的值保持i原样,在我们声明每个事件处理函数时,因此我们需要在每次迭代中捕获该值。使用声明后立即执行的匿名函数是捕获所需值的好机制。

另一点,稍微偏离主题但它可能会帮助你,是不是每个浏览器(ahem, IE )都支持事件捕获,但事件冒泡是。这有效地使useCapture布尔标志addEventListener对于开发跨浏览器 Web 应用程序毫无用处。因此,我建议不要使用它。

还有一件事,JavaScript 通常对函数名和变量名使用驼峰式大小写。Pascal 大小写通常仅用于构造函数(创建对象的函数)。

于 2010-04-07T22:13:43.707 回答
3

当您创建引用外部变量的函数时,这些引用将在您调用此函数时解析。

在你的情况下:

var functions = [];
function outer() {
    for (var i = 0; i < N; i++) { // <------------
        functions[i] = function() { //            |
            alert(i); // <-- this 'i' refers to this one
        }
    } // At the end of the for loop, i == N (or N+1?)
}
functions[x](); // Will show N (or N+1)
// because that's the current value of i in the outer function
// (which is kept alive just because something refers to it)

您想要做的是在循环的每个步骤中捕获 'i' 的值,以供以后评估,例如:

var functions = [];
function outer() {
    for (var i = 0; i < N; i++) { // <---------------------------------------
        functions[i] = (function(my_i) { // <----                            |
            return function () { //              |                           |
                alert(my_i); // my_i refers to this which is a copy of 'i' there
            }
        }(i)); // run function(with my_i = the i at each step of the loop)
    }
}
functions[x](); // Will show x

您可以看到有一个内部函数获取当前计数器的副本作为参数。该内部函数与该副本保持活动状态,因此稍后对存储的内部函数的调用返回创建它的函数的 my_i 的值 -- 清除?:-)

这就是闭包的美妙世界。第一次得到它可能需要一些思考,但你会很高兴你做到了,所以去谷歌搜索“javascriptclosures”吧!

于 2010-04-07T22:42:15.967 回答
2

这可能是 Russ Cam 答案的一个更明显的变体:

function Controls() {
  var Controls = document.getElementById("Quote_App").getElementsByTagName("dd");

  var createHandlerFor = function(CurrentControl) {
    return function() {
      var lorem=new Lorem(CurrentControl);
      lorem.Control=CurrentControl;
      alert(lorem.Amet());
    }
  };

  for (var i=0; i<Controls.length; i++) {
    Event("add", createHandlerFor(Controls[i]), "click", Controls[i]);
  }
};
于 2010-04-07T22:35:19.310 回答