Javascript闭包,函数总是指向数组中的最后一个对象

时间:2013-05-28 06:57:33

标签: javascript closures

大家好,我有以下代码

POINT = function () {
    that = {};
    that.x = 0; that.y = 0;

    that.setPoint = function (x, y) {
        that.x = x;
        that.y = y;
    };

    that.toString = function () {
        return that.x + ',' + that.y + ' ';
    };    

    return that;
};

PEN = function () {
    var that = {};
    var points = [];
    var buffer_size = 5, head = -1, length = 0;

    // Init buffer
    for (var i = 0; i < buffer_size; i++) {
        points.push(POINT());
    }

    that.addPoint = function (x, y) {
        head = (head + 1) % buffer_size;
        points[head].setPoint(x, y);
        if (length < buffer_size) {length++;}
    };

    that.toString = function (path) {
        var d = '';
        for (var i = 0; i < length; i++) {
            var index = (head - i) < 0 ? buffer_size + (head - i) : (head - i);
            d += points[index].toString();
        }
        return d;
    };

    return that;
};

// Initialization
var i = 0, pen = PEN();

for (var i = 0; i < 10; i++) {
    pen.addPoint(i + 1, i + 1);
}

alert(pen.toString()); // RESULT 10,10 10,10 10,10 10,10 10,10

points数组中填充了正确的pen个对象,但函数setPoint始终指向pen数组中的最后一个points对象。< / p>

注意:我希望可以直接访问xy坐标,因此我不会使用var将xy声明为“本地”变量。 / p>

这里有一个例子:http://jsfiddle.net/DNVjy/2/

3 个答案:

答案 0 :(得分:3)

你应该将你的变量放到var: - )

现在您正在定义窗口对象上的函数和本地“that”。现在代码不需要“那个”。

试试这个:

function POINT() {

    this.x = 0; this.y = 0;

    this.setPoint = function (x, y) {
        this.x = x;
        this.y = y;
    };

    this.toString = function () {
        return this.x + ',' + this.y + ' ';
    };    

    return this;
};

function PEN() {
    var points = [];
    var buffer_size = 5, head = -1, length = 0;

    // Init buffer
    for (var i = 0; i < buffer_size; i++) {
        points.push(new POINT());
    }

    this.addPoint = function (x, y) {
        head = (head + 1) % buffer_size;
        points[head].setPoint(x, y);
        if (length < buffer_size) {length++;}
    };

    this.toString = function (path) {
        var d = '';
        for (var i = 0; i < length; i++) {
            var index = (head - i) < 0 ? buffer_size + (head - i) : (head - i);
            d += points[index].toString();
        }
        return d;
    };

    return this;
};

你现在宣布这样一支笔:

var pen = new PEN();

(也请注意PEN“class”中的new POINT()个关键字。)

答案 1 :(得分:2)

that中的POINT更改为本地变量(位于其前面的var)会将输出更改为:
10,10 9,9 8,8 7,7 6,6

希望这是你一直期待的。更新了小提琴:http://jsfiddle.net/DNVjy/3/

答案 2 :(得分:1)

that中的POINT不应该是全球性的!每次创建一个全局变量时都会覆盖它,因此它们都引用同一对值。

FWIW,为什么不按照预期的方式使用JS对象?

function POINT() {
    if (this instanceof POINT) {
        this.x = 0; this.y = 0;
    } else {
        return new POINT();   // allow creation without "new"
    }
};

POINT.prototype.setPoint = function (x, y) {
    this.x = x;
    this.y = y;
};

POINT.prototype.toString = function () {
     return this.x + ',' + this.y + ' ';
};    

您使用的模块模式在许多方面都是次优的:

  • 每个实例都有自己的方法副本,而不是共享它们
  • 返回的对象没有特定的“类型”