2013-06-22 90 views
0

我正在嘗試創建2個正弦波並將它們添加到一起以創建第三個正弦波。我可以罰款,並將結果輸出將它們添加到控制檯,但每當我試圖把這個值到一個數組,我得到的錯誤:無法訪問Javascript變量:undefined

「不能未定義讀取屬性‘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]); 
} 
+0

聽起來像'D1 [I]'或'D2 [I]'不存在。如果'd1 [i]'沒有定義,當你push()時你不能'undefined [1]' –

+2

,你的元素會有整數索引,比如'2'。但是,你的i變量不是一個整數,它的東西就像'0.04' – goat

回答

4

要訪問的最後一個元素中dX使用dx[dX.length - 1]

你的i在這裏浮動(0.02)。該值不是一個整數,它被轉換爲一個字符串。然後,Array對象被解釋爲一個常規對象(一種地圖)。對象中沒有密鑰"0.02",因此dX["0.02"]的計算結果爲undefined。您無法訪問undefined,因此導致錯誤。

+1

*「該值不是一個整數,被轉換爲一個字符串。」*數組索引是* always *字符串。 (在經典的JavaScript數組中,不是新的)(不要誤解我的意思,我認爲我是你的第一個贊成的人,因爲這是第一個正確回答問題的答案,我只是說.. ) –

+0

數組索引從不是字符串。索引器語法a [value]訪問數組索引或對象屬性。如果使用類似[0]的數字,則該數字按原樣使用 - 不會轉換爲字符串 - 並訪問索引爲0的數組值(如果有)。如果您使用[[名稱]]之類的字符串,則會訪問名爲「名稱」的對象屬性(如果有)。這與訪問a.Name相同。 –

4

您試圖訪問陣列中的元素與雙打,因爲您的循環增加0.02。當您按下時,Array的鍵被設置爲整數,所以此方法不起作用。

我重構代碼中使用對象,而不是: 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]; 
} 
+0

@ T.J.Crowder確實,你是對的。我會稍微修改一下。 – Jivings

+0

@你在編輯之前評論過的。 – Jivings

+0

始終將相關代碼放在答案本身中,而不僅僅是鏈接。 (即使與jsFiddle。)爲什麼:http://meta.stackexchange.com/questions/118392/add-stack-overfow-faq-entry-or-similar-for-putting-code-in-the-question我在無論如何都要修正一個錯字,所以我只是把它複製給你。 –

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()是如何工作的。你傳遞一個值來推送它,並自動將它分配給數組中的下一個索引。因此,這與在它1個值的陣列上運行:

a.push([5, 10]); 

在索引1(未5)添加一個值,並且該值是本身有2項數組,[5, 10]。所以你這樣做的地方:

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

例如,您正在索引0處添加一個值,然後嘗試在索引爲0.02處將其取出。由於您的目標是通過索引直接訪問它們,因此使用push並不是很安全,然後假定索引與循環計數器中的內容匹配(例如,如果數組已經添加了值,該怎麼辦)。而是直接通過索引來分配,這在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/