无法访问Javascript变量:undefined

时间:2013-06-22 18:19:37

标签: javascript arrays undefined

我正在尝试创建2个正弦波并将它们组合在一起以创建第三个。我可以添加它们并将结果输出到控制台,但每当我尝试将此值放入数组时,我都会收到错误:

  

“无法读取未定义的属性'1'

谁能解释我哪里出错了? Jsfiddle:http://jsfiddle.net/YJqZz/

d1 = [];
d2 = [];
d3 = [];

// Sample the sine function
for (i = 0; i < 2 * Math.PI; i += 0.02) {
    d1.push([i, 15+Math.sin(5*i)]);
    d2.push([i, 10+Math.sin(4*i)]);
    console.log(d1[i][1] + d2[i][1]);
    d = d1[i][1] + d2[i][1];
    console.log(d);
    d3.push([i,d]);
}

3 个答案:

答案 0 :(得分:4)

要访问dX中的最后一个元素,请使用dx[dX.length - 1]

你的i浮在这里(0.02)。该值不是整数,而是转换为字符串。然后,Array对象被解释为常规对象(一种地图)。对象中没有键"0.02",因此dX["0.02"]的计算结果为undefined。您无法访问undefined,因此无法访问。

答案 1 :(得分:4)

您尝试使用双精度访问数组中的元素,因为您的循环增加0.02。当你按下时,数组的键被设置为整数,所以这个方法不起作用。

我重构了你的代码以改为使用Objects: http://jsfiddle.net/YJqZz/2/

d1 = {};
d2 = {};
d3 = {};

// Sample the sine function
for (i = 0; i < 2 * Math.PI; i += 0.02) {
  d1[i] = [i, 15+Math.sin(5*i)];
  d2[i] = [i, 10+Math.sin(4*i)];
  console.log(d1[i][1] + d2[i][1]);
  d = d1[i][1] + d2[i][1];
  console.log(d);
  d3[i] = [i,d];
}

答案 2 :(得分:1)

此代码存在很多问题。

首先,在这样的循环中添加浮点数会增加浮点格式的二进制错误,直到它们在输出中变得明显。尝试运行此代码:

var a = [];
for (var i = 0; i < 2 * Math.PI; i += 0.02)
    a.push(i);

$('#output').html(a.join('<br/>'));

http://jsfiddle.net/b9chris/AwT5c/

查看它生成的值。它可能不是你所期望的。那些疯狂的数字是浮点数存储方式的结果 - 小数部分存储为二进制小数,所以1/2 + 1/4 + 1/8 + .... 0.02不能以这种格式精确表示,因此系统将其近似,然后在返回时将值舍入为10的十进制小数,覆盖在捏造的基础值上。但是增加是以二进制形式完成的,最终近似值加起来并揭示了这个问题。

解决方案是用整数循环并尽可能晚地划分:

http://jsfiddle.net/b9chris/AwT5c/1/

其次,循环条件包括始终返回相同结果的操作。这会浪费CPU时间 - for循环将不断重新计算2 * Math.PI的值,以便在每个循环中获得完全相同的结果。您可以通过将其存储在变量中并对其运行循环来解决此问题。

您可能无法理解Array.push()的工作原理。您将一个值传递给push,它会自动将其分配给数组中的下一个索引。所以这个,在一个包含1个值的数组上运行:

a.push([5, 10]);

在索引1(而不是5)处添加值,该值本身就是一个2项数组[5, 10]。那么你在做什么:

d1.push([i, 1]);
var d = d1[i][1];

例如,您在索引0处添加了一个值,然后尝试在索引0.02处将其恢复。由于您的目标是通过索引直接访问它们,因此使用推送并不安全,然后假设索引与循环计数器中的内容匹配(例如,如果数组已经添加了值,该怎么办? )。而是直接按索引分配,这在Javascript中是允许的。

最后,您应该避免将所有内容转储到全局范围内 - 使用var关键字将它们作为本地范围。

var d1 = [];
var d2 = [];
var d3 = [];

var inverseStep = 50; // 1 / .02
var l = 2 * Math.PI * inverseStep;

for (var i = 0; i < l; i++) {
    var ix = i / inverseStep;

    d1[i] = [ix, 15+Math.sin(5*ix)];
    d2[i] = [ix, 10+Math.sin(4*ix)];
    var d = d1[i][1] + d2[i][1];
    d3[i] = [ix, d];
}

$('#output').html(d3.join('<br/>'));

http://jsfiddle.net/b9chris/AwT5c/3/