简体   繁体   English

如何避免“ this”引用DOM元素并引用对象

[英]How to avoid “this” refering to the DOM element, and refer to the object

I have a problem that I can't work around. 我有一个无法解决的问题。

The context is: I want to have an inheritance chain, and a method of objects that belong to this inheritance has to be a event handler, and at the same time be able to reach the object properties. 上下文是:我想拥有一个继承链,并且属于该继承的对象的方法必须是事件处理程序,并且同时能够访问对象属性。

I am giving a try to writing JavaScript without the "new" word, and using instead Object.create() with some inheritance hierarchy. 我正在尝试编写不带“新”字的JavaScript,并改为将Object.create()与某些继承层次结构一起使用。 So first this approach. 所以首先是这种方法。

So I have a blueprint for the rest of my objects (myProto), and then I create objects with Object.create (so that there is no closure where I can do the trick of assigning this to that or self ). 所以,我有我的其余对象(myProto)的蓝图,然后我创建的Object.create对象(所以没有封在那里我可以做到分配的把戏thisthatself )。 Now, when I use a method of this object to handle, for instance, a click event on a div, this obviously will refer to the DOM object, and I lose the posibility of accessing the properties of my object. 现在,当我使用该对象的方法来处理例如div上的click事件时, this显然将引用DOM对象,并且我失去了访问对象属性的可能性。

var myProto = {
    init: function (name, value) {
        this.name = name;
        this.value = value;

        return this;
    },
    someHandler: function (e) {
        // Normally I would use this instead of e.target...

        e.target.innerHTML = this.name + this.value; // This does not refer to the object.
    }
};

var myObject = Object.create(myProto).init('myName', 'myValue');
document.getElementById('myDiv').onclick = myObject.someHandler;

Here the fiddle: http://jsfiddle.net/pgPHM/ 这里的小提琴: http : //jsfiddle.net/pgPHM/

And now the "classical" approach: If I was using the new Constructor form, it would be easy to assign this in the closure and then access it, but there is the problem that the functions in the Constructor.prototype 现在是“经典”方法:如果我使用的是新的Constructor表单,则很容易在闭包中分配它然后访问它,但是存在Constructor.prototype中的函数的问题。

var Constructor = function (name, value) {
    var self = this;

    self.name = name;
    self.value = value;
};

Constructor.prototype.someHandler = function () {/*self does not reach this here*/};

jsfiddle: http://jsfiddle.net/ZcG3J/2/ jsfiddle: http : //jsfiddle.net/ZcG3J/2/

I really don't get why JS objects do not have a real this or self or whatever to refer to themselves without these tricky contexts, closures, etc... 我真的不明白为什么JS对象在没有这些棘手的上下文,闭包等情况下没有真正的thisself或任何引用自己的东西...

Basically the question is: 基本上,问题是:

How can I use a method of an object as an event handler, and still be able to reach the object? 如何使用对象的方法作为事件处理程序,并且仍然能够访问该对象?

Except for when using new , this in Javascript is set by according to how a function is called. 除了使用时newthis在Javascript中是按照函数是如何被调用设置。 Call it the right way and this will be what you want. 称呼正确, this就是您想要的。 I can't really tell what problem you're trying to solve in your question, but here's how this is determined. 我真的不能告诉你想在你的问题来解决什么问题,但在这里是如何this是确定的。

  1. Calling obj.method() - this will be set to obj inside of method() . 调用obj.method() - this将在method()内部设置为obj
  2. Use function.call() or function.apply() to control what this will be yourself. 使用function.call()function.apply()控制一下this将是你自己。
  3. Make a normal function call such as func() and this will be set to either the global object or undefined depending upon whether you're in strict mode. 进行正常的函数调用,例如func()this将被设置为全局对象或undefined具体取决于您是否处于严格模式下。
  4. Use .bind() (in modern browsers) to create a function stub that will automatically use .apply() internally to "bind" a value of this to the execution of the function. 使用.bind() (在现代浏览器中)创建一个函数存根,该存根将在内部自动使用.apply()将其值“绑定”到函数执行中。
  5. When you call a constructor using new , this will be set to the newly created object inside the constructor. 当您使用调用构造newthis将被设置为在构造函数中新创建的对象。
  6. When you pass a callback function as an argument to any function call (such as addEventListener() , it is the calling function's responsibility to decide what it wants the this pointer to be set to and won't be bound to your own object. addEventListener() sets this to be the DOM object that caused the event. 当你传递一个回调函数作为参数传递给任何函数调用(如addEventListener()它是调用函数有责任来决定它想要的this指针设置为,不会被绑定到自己的对象。 addEventListener() this设置为导致事件的DOM对象。

For event handlers that you want to be method calls on a particular object, you have to create a way to associate the method call with the object. 对于要成为特定对象上的方法调用的事件处理程序,必须创建一种将方法调用与该对象相关联的方法。 You can either use .bind() as specified above or use an anonymous function that can reference a saved value of this in a closure. 既可以使用.bind()如以上指定的,或使用可引用的保存的值的匿名函数this在封闭。

var self = this;
document.addEventListener('keyup', function(e) {
    self.handleKeys(e);
})

or, using .bind() : 或者,使用.bind()

document.addEventListener('keyup', this.handleKeys.bind(this));

FYI, there's not any real functional difference between these two methods because .bind() just creates a closure and does what the first example does, but does it for you. 仅供参考,这两种方法之间没有任何实际的功能差异,因为.bind()只是创建了一个闭包,并且执行了第一个示例中的操作,但是为您完成了此操作。

Simple. 简单。 If a function is called as a method instead of "bare" the this always refers to the word before the last dot. 如果某个函数被称为方法而不是“裸”,则this总是指最后一个点之前的单词。 So instead of: 所以代替:

document.getElementById('myDiv').onclick = myObject.someHandler;

// You're just passing the function here, not calling it.
// It will be called by the onclick handler so `this` is changed

do this: 做这个:

document.getElementById('myDiv').onclick = function(){
    myObject.someHandler();

    // Here, you're actually calling it. So this is the word
    // before the last dot. Which is myObject
}

In more modern javascript you can of course use bind : 在更现代的javascript中,您当然可以使用bind

document.getElementById('myDiv').onclick = myObject.someHandler.bind(myObject);

The first problem in your jsfiddle is that self is a local variable for Constructor and it is not available outside of the function. jsfiddle中的第一个问题是self是Constructor的局部变量,在函数外部不可用。 What you think about the following code: 您对以下代码的看法:

var Constructor = function(name, value) {
    var self = this;
    self.name = name;
    self.value = value;
    self.someHandler = function(e) {
        e.target.innerHTML = self.name + self.value; // self undefined    
    }
    return self;
};

var myObject = Constructor('myName', 'myValue');
document.getElementById('myDiv').onclick = myObject.someHandler;

JsFiddle -> http://jsfiddle.net/ZcG3J/4/ JsFiddle-> http://jsfiddle.net/ZcG3J/4/

Is it structured as you want? 是否按您想要的结构?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM