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

时间:2013-10-27 21:21:40

标签: javascript oop inheritance this

我遇到了一个无法解决的问题。

上下文是:我想拥有一个继承链,属于这个继承的对象的方法必须是一个事件处理程序,同时能够到达对象属性。

我试着编写没有“new”字的JavaScript,而是使用Object.create()和一些继承层次结构。首先是这种方法。

所以我对其余的对象(myProto)有一个蓝图,然后用Object.create创建对象(这样就没有闭包,我可以把this分配给{{ 1}}或that)。现在,当我使用此对象的方法来处理div上的click事件时,self显然会引用DOM对象,并且我失去了访问对象属性的可能性。 / p>

this

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

现在是“经典”方法:如果我使用的是新的构造函数表单,那么很容易在闭包中分配它然后访问它,但是存在Constructor.prototype中的函数的问题

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;

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

我真的不明白为什么JS对象没有真正的var Constructor = function (name, value) { var self = this; self.name = name; self.value = value; }; Constructor.prototype.someHandler = function () {/*self does not reach this here*/}; this或者在没有这些棘手的上下文,闭包等的情况下引用自己......

基本上问题是:

如何将对象的方法用作事件处理程序,并且仍然能够到达对象?

3 个答案:

答案 0 :(得分:2)

除了使用new时,Javascript中的this是根据函数的调用方式设置的。以正确的方式调用它,this将是您想要的。我无法确定你在问题中想要解决的问题,但是this是如何确定的。

  1. obj.method()内拨打this - obj将设置为method()
  2. 使用function.call()function.apply()来控制自己this的内容。
  3. 正常的函数调用,例如func()this将被设置为全局对象或undefined,具体取决于您是否处于严格模式。
  4. 使用.bind()(在现代浏览器中)创建一个函数存根,它将在内部自动使用.apply()将此值“绑定”到函数的执行中。
  5. 使用new调用构造函数时,this将设置为构造函数内新创建的对象。
  6. 当您将回调函数作为参数传递给任何函数调用(例如addEventListener()时,调用函数有责任决定它需要将this指针设置为并赢得'绑定到您自己的对象。addEventListener()this设置为导致该事件的DOM对象。
  7. 对于要对特定对象进行方法调用的事件处理程序,必须创建一种将方法调用与对象关联的方法。您可以使用上面指定的.bind()或使用可以在闭包中引用保存的this值的匿名函数。

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

    或使用.bind()

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

    仅供参考,这两种方法之间没有任何真正的功能差异,因为.bind()只是创建一个闭包并执行第一个示例所做的事情,但是它适合您。

答案 1 :(得分:2)

简单。如果函数被称为方法而不是“裸”,则this始终引用最后一个点之前的单词。所以而不是:

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

这样做:

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
}

在更现代的JavaScript中,您当然可以使用bind

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

答案 2 :(得分:1)

你的jsfiddle中的第一个问题是self是Constructor的局部变量,它在函数外部不可用。您对以下代码的看法如下:

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/

它的结构是否符合您的要求?