0

下面是从 SlickGrid 示例派生的非常简化的代码片段:

模型.js:

(function($) {
    function RemoteModel() {
        var someArr=[0];
        var someVar=0;
        var onDataLoadedSuccess = new Slick.Event();

        function ensureData(from, to) {
            h_request = setTimeout(function() {
                req = $.ajax({
                    url: url,
                    context: this,
                    success: function(resp) {
                        onSuccess();
                    }
                });
            }, 3000);
        }

        function onSuccess() {
            someVar=someVar+100;
            someArr[0]=someArr[0]+100;
            console.log(someVar + " " + someArr[0]); // yes values are changing properly for both !

            onDataLoadedSuccess.notify({ from: from, to: to });
        }

        return {
            "someArr": someArr,
            "someVar": someVar,
            "onDataLoadedSuccess": onDataLoadedSuccess,
        };
    }
})(jQuery);

主.js:

var loader=new RemoteModel();
var grid=new Slick.Grid("#wlGrid", loader.data, columns, options);

grid.onViewportChanged.subscribe(function(e, args) {
    var vp = grid.getViewport();
    loader.ensureData(vp.top, vp.bottom);
});

loader.onDataLoadedSuccess.subscribe(function(e, args) {
    // someVar is always 0 :( ! someArr[0] is changing fine .. why ???
    console.log(loader.someVar + " " + loader.someArr[0]); 
});

因此,网格 () 上的一个事件onViewportChanged正在调用ensureData模型,这会增加someVarsomeArr[0],这两者都由 的返回值公开RemoteModel

增加事件后,onDataLoadedSuccess由模型触发,但是在该事件中,只有 的值发生loader.someArr[0]了变化。

为什么someVarin的值onDataLoadedSuccess总是为零?这是范围问题吗?为什么someArr[0]改变罚款的价值?

如何正确读取someVarin的值onDataLoadedSuccess

4

5 回答 5

0

创建模型时,您将其返回给loader

return {
  "someArr": someArr,
  "someVar": someVar,
  "onDataLoadedSuccess": onDataLoadedSuccess,
}

loader.someArrsomeArr指向闭包中指向的同一个数组。someVar但是,它是一个值为 0 的属性,从闭包中复制而来someVar

当使用对象(包括数组)分配变量或对象属性时,您正在引用该对象。因此,指向闭包loader.someArr中指向的同一个数组。someArr可以通过两者进行更改someArrloader.someArr因为它们指向同一个数组。

但在 的情况下,您从someVar分配。由于是原始值,因此该值从复制到。因此,不要指向同一件事。修改不会修改,反之亦然。loader.someVarsomeVar0someVarloader.someVarsomeVarloader.someVarsomeVarloader.someVar

于 2013-04-03T07:07:19.417 回答
0

该函数具有和的RemoteModel局部变量。这些也作为对象属性在创建时返回。不同之处在于,数字 for 的值在创建时被有效地复制到其中。someVarsomeArrloadersomeVarloader

该数组也被复制到其中someArr,但该副本是通过引用进行的。因此,您有两件事指向同一个数组。当事件执行时,它会更新局部变量和局部数组。loader指向同一个数组,所以你看到了someArr[0]变化,但它没有“指向”数字,所以当本地someArr被改变时,loader值不是。

编辑以解决评论

一种选择是首先定义您返回的对象,然后让您的私有函数引用它。这可能仅限于数字或适用于所有公共成员;为了清楚起见,我会做后者。使用这种方法,只需要更改类,而不是调用它的代码。

function RemoteModel() {
    var ret = {
        "someArr": [0],
        "someVar": 0,
        "onDataLoadedSuccess": new Slick.Event()
    };        

    function onSuccess() {
        ret.someVar=ret.someVar+100;
        // ...
    }

    return ret;
    // ...

第二种选择是getSomeVar在返回的对象中创建一个方法,以便在类之外执行loader.getSomeVar()而不是仅仅loader.someVar. setSomeVar(newValue)(如果它需要外部可设置,您可以创建一个。

function RemoteModel() {
    var someVar=0;
    // ...

    function getSomeVar() {
        return someVar;
    }

    return {
        "someArr": someArr,
        "getSomeVar": getSomeVar,
        "onDataLoadedSuccess": onDataLoadedSuccess,
    };
}

进而:

loader.onDataLoadedSuccess.subscribe(function(e, args) {
    console.log(loader.getSomeVar() + " " + loader.someArr[0]); 
});
于 2013-04-03T07:07:56.940 回答
0

数字和其他非对象原语按值返回,而不是按引用返回:

    return {
        "someArr": someArr, // <-- object
        "someVar": someVar, // <-- number
        "onDataLoadedSuccess": onDataLoadedSuccess,
    };

someArr是一个对象(数组),将通过引用返回。然而someVar,这只是一个简单的数字。因此,您将返回一个值。

RemoteModel而不是在你的你应该使用RemoteModel一个适当的构造函数返回一个对象:

    this.someArr=[0];
    this.someVar=0;
    this.onDataLoadedSuccess = new Slick.Event();

    /* move other functions into the prototype, get rid of the return */

如果您不熟悉将函数用作构造函数,请参阅MDN 上的使用对象

于 2013-04-03T07:09:36.613 回答
0

这是因为 javascript 如何处理这些值。

(function($) {
    function RemoteModel() {
        this.someArr=[0];
        this.someVar=0;
        this.onDataLoadedSuccess = new Slick.Event();

        var _this = this;

        function ensureData(from, to) {
            h_request = setTimeout(function() {
                req = $.ajax({
                    url: url,
                    context: this,
                    success: function(resp) {
                        onSuccess();
                    }
                });
            }, 3000);
        }

        function onSuccess() {
            _this.someVar=_this.someVar+100;
            _this.someArr[0]=_this.someArr[0]+100;
            console.log(_this.someVar + " " + _this.someArr[0]); // yes values are changing properly for both !

            _this.onDataLoadedSuccess.notify({ from: from, to: to });
        }
    }
})(jQuery);
于 2013-04-03T07:10:14.530 回答
0

那是因为在你回来的那一刻

{
        "someArr": someArr,
        "someVar": someVar,
        "onDataLoadedSuccess": onDataLoadedSuccess,
};

someVar0

someVar持有 a String,一个原始类型。

someArr引用Array非原始类型。

字符串(和其他原始类型按值 传递,数组(和其他非原始类型引用传递。更具体地说:对 Object 的变量引用按值传递(传递时新 var 保存引用的副本)

所以你返回的是你的字符串的“副本”

于 2013-04-03T07:14:51.377 回答