JavaScript:全局数组变量返回未定义

3

我是一名JavaScript新手。我已经搜索了很多答案,但似乎无法解决这个问题。我将数组传递给函数时,它们没有被正确地作为引用传递。我不认为这是异步问题,尽管许多帖子都在暗示这一点,但我可能错了。

我有一些全局数组,我将它们传递给函数。在函数内部,数组返回其正确的值,但是当我尝试在函数外部访问它们时,它们是未定义的。

为了上下文,我正在传递3个数组,它们保存干球温度、湿球温度和测量时间的小时数,以便进行后续计算。出于简洁起见,我仅包含了一些样本数据点。以下是示例代码:

function run(){
    var hour = [];
    var db = [];
    var wb = [];
    var cities = ["AB Edmonton","MI Detroit"];
    getData(hour, db, wb, cities); 
    //this shows undefined, although within getData it is accurate data
    alert(hour[1]);
}

function getData(hour, db, wb, cities){
    //i= drop-down selection index, set to zero for testing
    i=0;

    switch(cities[i]) {
        case "AB Edmonton":
            hour = [1,2,3];
            db = [15,18,21];
            wb = [10,13,20];
            break;
        //case "MI Detroit":....
    }

    //this shows accurate values in the alert window
    alert(cities[i] + " at hour:" + hour[i] + " the temp is:" + db[i]);

    return [hour, db, wb];
};

你可以将城市传递到你的 getData 函数中,或者在函数外部定义它。目前,cities 只在 run 中被定义,getData 无法访问它。确保研究闭包。 - Dom
1
但它们不是全局数组。您已将它们指定在run函数内部,因此它们只具有该范围。 - Leo Farmer
如果您没有收到返回的数据,为什么要将它们返回呢? - XCS
所以,我无法告诉你为什么会发生这种情况,但它与小时范围有关。如果你在函数外定义变量(不使用var,例如hour = 0),你的代码就不应该返回未定义。 - grill
getData(); 放入一个变量中。我认为你不需要将 hour, db, wb 传递给函数,你只需要传递 cities - Abhi
4个回答

3

run函数将空数组赋值给hourdbwb。这些变量是局部作用域的。

然后它调用getData并将这些数组作为参数传递。

getData内部,声明了新的局部变量(也命名为hourdbwb),并将在调用函数时传递的三个空数组赋值给它们。

然后函数忽略这些值,并使用新数组(这些数组具有内容)覆盖它们。

然后它返回另一个新数组,其中包含每个数组。

这使我们回到了run函数。完全忽略getData的返回值,并访问原始数组(仍存储在属于runhourdbwb变量中,但它们仍为空)。

你可以:

  • getData内部操作现有数组,而不是覆盖它们。 (例如,hour = [1,2,3] 可以变成 hour.push(1); hour.push(2); hour.push(3))。
  • 使用getData的返回值(在这种情况下,你不需要在第一次赋值或传递空数组时麻烦地分配值)。你可以使用对象而不是数组,因此你也可以在这里拥有有用的名称而不是顺序。

如下:

function run(){
    var cities = ["AB Edmonton","MI Detroit"];
    var data = getData(cities); 
    alert(data.hour[1]);
}

function getData(cities){
    //i= drop-down selection index, set to zero for testing
    var i=0; // Use locally scoped variables where possible
    var hour, db, wb;

    switch(cities[i]) {
        case "AB Edmonton":
            hour = [1,2,3];
            db = [15,18,21];
            wb = [10,13,20];
            break;
        //case "MI Detroit":....

    //this shows accurate values in the alert window
    alert(cities[i] + " at hour:" + hour[i] + " the temp is:" + db[i]);

    return { hour: hour, db: db, wb: wb];
};

1

好的,这些不是全局变量。其中一个名为hour的变量是在run()中声明的局部变量,使用var进行声明,另一个变量是在getData函数中声明的参数,也是局部变量。

在您的getData函数中,您正在覆盖本地变量(最初具有由run()传递的值)的行中。

 hour = [1,2,3];

从那时起,这两个变量引用不同的数组。

0
function getData(hour, db, wb, cities){ }

hourdb等等是对初始数组的引用。

当你写hour = [1,2,3];时,hour的局部引用不再指向你想要的数组,而是指向一个新构建的数组:[1,2,3]。要解决这个问题,只需将值推入参数中 hours.push(1,2,3); 这样就不会覆盖你的引用。

这是当你执行以下操作时发生的同样问题:

a = {x : 1};
function setX(obj) {
  obj = {x: 2};
}
function correctSetX(obj) {
  obj.x = 2;
}

在编程中,setX 函数不会做任何事情,而 correctSetX 函数将正确地将 {x: 2} 赋值给变量。


0

感谢大家的帮助!我根据评论发布了我的代码编辑方式,实现了代码运行。以下是一些需要说明的点:

-我将所有变量移动到getData()函数中作为局部变量。其中至少有一个评论给人留下了变量保持本地化的好处的印象(非常抱歉,我不是计算机科学专业出身,但是我很感激你们的建议和耐心)

-由于数据量太大(每年至少有8760个测量值),我无法简单地使用.push方法。我记不得确切的错误了,但与堆栈限制相关。

-在Quentin的建议下,我创建了一个具有数组属性的dataSet对象。这个对象是由getData函数返回的。再次感谢,这是处理此问题的更好方法。

以下是示例(仅包含有限数据):

function run(){

    //get data
    var dataSet = getData(); 
    //test the result on the 2 hour reading
    alert(dataSet.hour[1]); 
}

function getData(){
//i= drop-down selection index, set to zero for testing
var i=0;
var hour,db,wb;
var cities = ["AB Edmonton","MI Detroit"];
switch(cities[i]){

    case "AB Edmonton":
        hour = [1,2,3];
        db = [10,11,12];
        wb = [13,14,15];
        break;
    //case "MI Detroit":...
} //end of switch

return {hour: hour, db: db, wb: wb};
}; //end of getData

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接