似乎javascript范围不正确。它看起来不像正常的范围问题,因为使用.call()或.bind()仍会导致错误的范围。具体的代码使用Knockout和LoDash,但我不认为这两个库都与这个bug有关。核心代码元素如下:
var FacilityDisplayModel = function (facility, options) {
var self = facility ? facility : this;
self.Areas = ko.observableArray();
...
self.hydrate = function (facilityHierarchy)
{
...
var areas = facilityHierarchy.Areas()
for (var i in areas)
{
new AreaDisplayModel(areas[i], self, options);
}
self.Areas(areas);
...
}
self.hydrateHasCars = function(trackListWithoutCars){
var hasCars = false;
_.forEach(self.Areas(), function (area) {
if(area.hydrateHasCars(trackListWithoutCars)) hasCars = true;
});
...
}
return self;
}
var AreaBaseModel = function (area, parent, options) {
var self = area ? area : this;
if (self.Areas) {
for (var i in self.Areas()) {
new AreaDisplayModel(self.Areas()[i], self, options);
}
}
...
return self;
}
var AreaDisplayModel = function (area, parent, options) {
self = new AreaBaseModel(area, parent, options);
self.Name;
self.hydrateHasCars = function(trackListWithoutCars) {
var hasCars = false;
_.forEach(self.Areas(), function(area) {
if (area.hydrateHasCars(trackListWithoutCars)) hasCars = true;
});
}
...
return self;
}
这个问题是使用.call()或作为普通函数调用.hydrateHasCars()会导致结果的范围错误。它最终使用当前实例范围而不是子范围。
例如,我们所在的区域名称为“区域1”。当我们通过区域前进时,第一个区域被称为“区域1.1”。这是同一对象的单独实例。但是在“区域1.1”上调用.hydrateHasCars()会导致“区域1”的自我。即使使用.call(area,...),特别是将范围设置为“Area 1.1”,它仍然会产生“区域1”的“自我”范围。
编辑:我已更新代码段以包含更多代码。我已尽可能多地考虑可能与此问题相关。代码流是这样的:一个设施用来自服务器的信息,建立区域,下面有子区域。然后,我们从服务器获取汽车信息并浏览这些区域,进行更新。我们需要知道子区域是否有汽车才能知道它的父区是否有汽车。这里是范围问题,其中父区域调用子区域,但是在调试时,我可以看到调用中的“self”是指父级而不是子级。
我发现的解决方法是将hydrateHasCars视为“静态”并传递到以下区域:
self.hydrateHasCars = function(parentArea, trackListWithoutCars) {
var hasCars = false;
_.forEach(parentArea.Areas(), function(area) {
if (area.hydrateHasCars(area, trackListWithoutCars)) hasCars = true;
});
};
但是,我宁愿使用非“静态”方法并修复范围问题。