对象中的 AddEventListener

AddEventListener with in a object

我可能需要你的帮助,目前我正在尝试通过 addEventListener 激活来调用对象内的方法。问题是一旦调用该方法,this 指针就会发生变化。我尝试使用 .call 为方法返回正确的上下文,它按预期工作,但这是最好的方法吗?

<!doctype html>
<html>
    <head>
        <title>Java Script Test</title>
        <meta charset="UTF-8" />
   <!-- <script src="//code.jquery.com/jquery-1.11.2.min.js"></script> -->
        <script src="../resurces/js/jquery-1.11.2.min.js" ></script>
        <script>
            var test_class = function(){
                this.variable = "more text";
                this.click = function(){
                    $("#return").text("Content: "+this.variable);
                }
                this.aktivate_listener = function(){
                    var that = this;
                    document.getElementById("clicker").addEventListener("click", function(){that.click.call(that)});
                }

            }

            $("document").ready(function(){
                console.log("#ready");
                var class1 = new test_class();
                class1.aktivate_listener();

            });
        </script>
    </head>
    <body>
        <p id="clicker">This is some Text to click on.</p>
        <p id="return"></p>
    </body>
</html>

你们中有人知道更好的方法吗?

感谢您的努力, 弗洛

基本上没问题,但有几点:

  1. 您无需执行 that.click.call(that) - 只需 that.click() 即可。

  2. 您没有传递匿名函数接收的事件对象。如果你不需要它,那很好,但我想我会提到它。

另一种选择是使用 Function#bind:

this.aktivate_listener = function(){
    document.getElementById("clicker").addEventListener("click", this.click.bind(this));
}

Function#bind returns 一个函数,当被调用时,返回并调用原始函数 this 设置为特定值。因此 this.click.bind(this) 创建了一个函数,当调用该函数时,将在对象上调用 clickthis 引用该对象。绑定函数的任何参数都会在调用基础函数时传递。


回复您的评论:

But I read that you can't remove an EventListener that is created with .bind A problem in the example above is that you cannot remove the listener with bind. That is taken from the Mozilla Developer Network.

如果是这样,MDN 是错误的。它是社区编辑的,发生了。 :-)

就能够使用 removeEventListener 删除处理程序而言,您的代码与使用上述 Function#bind 完全没有区别 :您如果不更改代码以记住我们传递给 addEventListener.

的内容,则无法在任何一种情况下删除侦听器

使用 bind 的事件处理程序没有什么特别之处。就像任何其他事件处理程序一样,如果你想用 removeEventListener 删除它,你必须引用你在删除它时添加的 相同的函数 。在您的代码中,这将是您包裹在 that.click.call(that); 周围的匿名函数,并且由于您没有保留对它的引用,所以您无法删除它。同样,在我上面的代码中,您不能删除侦听器,因为我没有保留对绑定函数的引用。

如果这是您需要做的事情,请记住您要删除的函数——这是对您的匿名函数的引用,或者是对 Function#bind 返回函数的引用。例如,您可以将它存储在您的对象上。

this.aktivate_listener = function(){
    if (this.boundClick) {
        this.deaktivate_listener();
    }
    this.boundClick = this.click.bind(this);
    document.getElementById("clicker").addEventListener("click", this.boundClick);
};
this.deacktivate_listener = function(){
    document.getElementById("clicker").removeEventListener("click", this.boundClick);
    this.boundClick = null;
};

再次查看您的代码,您有第三种选择:您的 click 函数是对创建实例的 test_class 调用的闭包,因此您不需要创建另一个闭包,只用你已有的:

var test_class = function(){
    // Remember `this` in a variable
    var self = this;
    this.variable = "more text";
    this.click = function(){
        // Use it here
        $("#return").text("Content: "+self.variable);
    };
    this.aktivate_listener = function(){
        // Just use `this.click` here
        document.getElementById("clicker").addEventListener("click", this.click);
    };
    this.deaktivate_listener = function(){
        // Just use `this.click` here
        document.getElementById("clicker").removeEventListener("click", this.click);
    };
};

旁注:您需要在 var f = function() { }; 等语句末尾添加 ;,因为它们是语句,而不是声明。我已经在上面添加了它们。如果您不提供,大多数时候自动分号插入会为您添加,但如果您不小心,可能会出错。


以上所有的例子:

你的方式没有 .call(没有 deaktivate):

var Test = function(id, name) {
  this.id = id;
  this.name = name;
  this.click = function() {
    snippet.log("My name is " + this.name);
  };
  this.aktivate_listener = function() {
    var that = this;
    document.getElementById(this.id).addEventListener(
      "click",
      function() { that.click(); },
      false
    );
  };
};
var t1 = new Test("one", "test one");
t1.aktivate_listener();
var t2 = new Test("two", "test two");
t2.aktivate_listener();
<div id="one">Click me (one)</div>
<div id="two">Click me (two)</div>

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

使用 Function#bind(没有去激活):

var Test = function(id, name) {
  this.id = id;
  this.name = name;
  this.click = function() {
    snippet.log("My name is " + this.name);
  };
  this.aktivate_listener = function() {
    document.getElementById(this.id).addEventListener(
      "click",
      this.click.bind(this),
      false
    );
  };
};
var t1 = new Test("one", "test one");
t1.aktivate_listener();
var t2 = new Test("two", "test two");
t2.aktivate_listener();
<div id="one">Click me (one)</div>
<div id="two">Click me (two)</div>

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

使用现有的闭包(没有 deaktivate):

var Test = function(id, name) {
  var self = this;
  this.id = id;
  this.name = name;
  this.click = function() {
    snippet.log("My name is " + self.name);
  };
  this.aktivate_listener = function() {
    document.getElementById(this.id).addEventListener(
      "click",
      this.click,
      false
    );
  };
};
var t1 = new Test("one", "test one");
t1.aktivate_listener();
var t2 = new Test("two", "test two");
t2.aktivate_listener();
<div id="one">Click me (one)</div>
<div id="two">Click me (two)</div>

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

你的方式没有 .call(有 deaktivate):

var Test = function(id, name) {
  this.id = id;
  this.name = name;
  this.counter = 0;
  this.click = function() {
    snippet.log("My name is " + this.name);
    if (++this.counter == 2) {
      this.deaktivate_listener();
    };
  };
  this.aktivate_listener = function() {
    var that = this;
    if (this.boundClick) {
      this.deaktivate_listener();
    }
    this.boundClick = function() { that.click(); };
    document.getElementById(this.id).addEventListener(
      "click",
      this.boundClick,
      false
    );
  };
  this.deaktivate_listener = function() {
    if (this.boundClick) {
      document.getElementById(this.id).removeEventListener(
        "click",
        this.boundClick,
        false
      );
      this.boundClick = null;
    }
  };
};
var t1 = new Test("one", "test one");
t1.aktivate_listener();
var t2 = new Test("two", "test two");
t2.aktivate_listener();
<div id="one">Click me (one) (second click deactivates)</div>
<div id="two">Click me (two) (second click deactivates)</div>

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

使用 Function#bind(使用 deaktivate):

var Test = function(id, name) {
  this.id = id;
  this.name = name;
  this.counter = 0;
  this.click = function() {
    snippet.log("My name is " + this.name);
    if (++this.counter == 2) {
      this.deaktivate_listener();
    };
  };
  this.aktivate_listener = function() {
    if (this.boundClick) {
      this.deaktivate_listener();
    }
    this.boundClick = this.click.bind(this);
    document.getElementById(this.id).addEventListener(
      "click",
      this.boundClick,
      false
    );
  };
  this.deaktivate_listener = function() {
    if (this.boundClick) {
      document.getElementById(this.id).removeEventListener(
        "click",
        this.boundClick,
        false
      );
      this.boundClick = null;
    }
  };
};
var t1 = new Test("one", "test one");
t1.aktivate_listener();
var t2 = new Test("two", "test two");
t2.aktivate_listener();
<div id="one">Click me (one) (second click deactivates)</div>
<div id="two">Click me (two) (second click deactivates)</div>

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

使用现有闭包(带 deaktivate):

var Test = function(id, name) {
  var self = this;
  this.id = id;
  this.name = name;
  this.counter = 0;
  this.click = function() {
    snippet.log("My name is " + self.name);
    if (++self.counter == 2) {
      self.deaktivate_listener();
    };
  };
  this.aktivate_listener = function() {
    document.getElementById(this.id).addEventListener(
      "click",
      this.click,
      false
    );
  };
  this.deaktivate_listener = function() {
    document.getElementById(this.id).removeEventListener(
      "click",
      this.click,
      false
    );
  };
};
var t1 = new Test("one", "test one");
t1.aktivate_listener();
var t2 = new Test("two", "test two");
t2.aktivate_listener();
<div id="one">Click me (one) (second click deactivates)</div>
<div id="two">Click me (two) (second click deactivates)</div>

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

这是我目前使用的版本,由@T.J制作而成。克劳德回答。

function boxOperator(){
    this.event      = [];

    this.addEvent = function(element, event, tocall_function, arg){         
        var call_function = tocall_function.bind(this, arg);
        this.event[this.event.length] = {
            "element"       : element,
            "event"         : event,
            "call_function" : call_function
        };
        document.getElementById(element).addEventListener(event,call_function);
    };

    this.removeEvent = function(element, event){
        if(!element){return false;};
        var remove_entry = function(index, array){return array.slice(0,index-1).concat(array.slice(index+1));}
        for(var i = 0; i < this.event.length;i++){
            if(this.event[i].element == element){
                var entry = this.event[i];
                if(entry.event == event){
                    document.getElementById(entry.element).removeEventListener(entry.event,entry.call_function);
                    this.event = remove_entry(i, this.event);
                }               
                if(typeof event == "undefined"){
                    document.getElementById(entry.element).removeEventListener(entry.event,entry.call_function);                
                    this.event = remove_entry(i, this.event);
                }
            }
        }
    };
}