以下是从SlickGrid示例派生的大大简化的代码片段:
model.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);
main.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
增加someVar
和someArr[0]
,两者都由返回值公开
RemoteModel
。
在递增事件后,模型会触发onDataLoadedSuccess
在该事件中,只有loader.someArr[0]
的值发生了变化。
为什么someVar
中onDataLoadedSuccess
的值始终为零?这是范围问题吗?
为什么someArr[0]
的值变化很好?
如何正确阅读someVar
中的onDataLoadedSuccess
的值?
答案 0 :(得分:0)
创建模型时,将其返回到loader
:
return {
"someArr": someArr,
"someVar": someVar,
"onDataLoadedSuccess": onDataLoadedSuccess,
}
loader.someArr
指向闭包中someArr
指向的相同数组。但是,someVar
是一个值为0的属性,从封锁中的someVar
复制。
使用对象(包括数组)分配变量或对象属性时,您将引用该对象。因此,loader.someArr
指向闭包中someArr
指向的相同数组。可以通过someArr
和loader.someArr
进行更改,因为它们指向同一个数组。
但是在someVar
的情况下,您从loader.someVar
分配了someVar
。由于0
是原始值,因此值从<{1}}复制到someVar
。因此,loader.someVar
和someVar
并未指向同一事物。修改loader.someVar
不会修改someVar
,反之亦然。
答案 1 :(得分:0)
RemoteModel
函数包含someVar
和someArr
的局部变量。这些也在创建loader
时作为对象属性返回。不同之处在于someVar
的数字值在创建时有效地复制到loader
。
数组也被复制到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]);
});
答案 2 :(得分: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 */
如果您不熟悉将函数用作构造函数,请参阅Working with Objects on MDN。
答案 3 :(得分: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);
答案 4 :(得分:0)
多数民众赞成在你回来的那一刻
{
"someArr": someArr,
"someVar": someVar,
"onDataLoadedSuccess": onDataLoadedSuccess,
};
someVar
是0
。
someVar
拥有String
,一种原始类型。
someArr
引用Array
非原始类型。
字符串(以及其他原始类型) 通过引用传递按值,数组(以及其他非原始类型)。 更具体:对象的变量引用按值传递(传递时,新的var包含引用的副本)
所以你返回的是你的String的“副本”