在jquery事件中发出引用对象实例的问题

时间:2014-05-02 11:59:18

标签: javascript jquery

首先,我是面向对象JS的新手,但对JS和jQuery很有经验。

我遇到的问题毫无意义,在代码中有更好的解释,请参阅下文:

var $table = $("tbody#peopleContainer"); // hypothetical table to which we will append rows for each person object

var Person = function( name ) { //nothing special here
    this.name = name;
    this.nickname = "";
}
Person.prototype = {
    create: function() {
        $tr = $table.append("<tr></tr>"); //create a blank row

        this.$name = $('<td>'+this.name+'</td>').appendTo( $tr );
        this.$nickname = $('<td><input type="text"></td>').appendTo( $tr );

        $table.append( this.$td ).append( this.$nickname ); 

        self = this;
        this.$name.on("click", $.proxy(self.logName, self)); // logs the name of the person's row you clicked
        $("input", this.$nickname).change(function() { // Should log the nickname you typed as well as the person's name whose nickname you changed
            self.nickname = $(this).val();
            $.proxy(self.logNameAndNickname, self)();  // Problem! Logs the nickname you typed in, but ALWAYS logs the last instantiated person's name
        })
    },
    logName: function() {
        console.log(this.name);
    },
    logNameAndNickname: function() {
        console.log(this.name, this.nickname); // for some reason this.name returns the last instantiated person's name (Person #0).
    }
}

// create 100 people and append to table
x = 100;
while ( x-- > 0 ) {
    person = new Person("Person #"+x);
    person.create();
}

由于某种原因,logName()会记录正确的人的姓名,但logNameAndNickname()始终记录最后一个实例化的人的姓名,尽管它会记录正确的昵称。好像this引用了同一范围内的2个独立对象。

所以我的问题是 - 这里发生了什么?

后续问题:这是将jQuery事件与对象一起使用的正确方法吗?我是面向对象JS的新手,所以请告诉我是否有更合适的方法来完成同样的事情。

2 个答案:

答案 0 :(得分:1)

问题在于

1)self是一个全局变量(用var关键字定义),每次创建一个Person时都会被“覆盖”。

2)然后您代理logNamelogNameAndNickname,将这些函数中的this引用替换为self,这将始终引用 last 创建的人员

答案 1 :(得分:0)

self是一个无意中的全局变量,它将被每个构造函数覆盖,然后在while循环之后保存最后一个实例。您需要将其设置为构造函数范围的本地。

此外,如果您使用$.proxy,那么 需要使用self,如果您使用self >需要使用$.proxy

this.$name.on("click", $.proxy(this.logName, this));
/* is equivalent to 
var self = this;
this.$name.on("click", function() {
    self.logName()
}); */

var self = this;
this.$nickname.find("input").change(function() {
    self.nickname = $(this).val();
    self.logNameAndNickname();
});
/* or
this.$nickname.find("input").change($.proxy(function(e) {
    this.nickname = e.target.value;
    this.logNameAndNickname();
}, this)); */