2012-02-25 240 views
-1

我有一個腳本一直告訴我ctx是未定義的,但仍然在腳本中設置了不同的變量,這是在同一個地方創建的......所以我很困惑爲什麼要設置一個變量而不是其他變量。未定義的ctx變量

錯誤是: 未捕獲的ReferenceError:CTX沒有在線路32上所定義(I註釋行32)

然而變種畫布定義=/

這是我的腳本:

var tiles = Array("1.png","0.png"); 
var loaded = 0; 
var loadTimer; 


function loadimg(){ 
var tileImg = new Array(); 
for(var i=0;i<tiles.length;i++){ 
    tileImg[i] = new Image(); 
    tileImg[i].src = tiles[i]; 
    tileImg[i].onload = function(){ 
     loaded++; 
    } 
    } 
} 

function loadall(){ 
if(loaded == tiles.length){ 
    clearInterval(loadTimer); 
    loadTimer = setInterval(gameUpdate,100); 
} 
} 

function gameUpdate(){ 
ctx.clearRect(0,0,canvas.width,canvas.height); //line 32 
draw(); 
} 

function init(){ 
var canvas = document.getElementById("canvas"); 
var ctx = canvas.getContext("2d"); 
loadimg(); 
loadTimer = setInterval(loadall,100); 
} 

希望你能幫助解釋我的錯誤。

回答

2

這完全是關於作用域,變量將只存在於它定義的代碼塊中。將您的定義移到代碼的頂部。

var tiles = Array("1.png","0.png"); 
var loaded = 0; 
var loadTimer; 
var ctx; 
var canvas; 

function loadimg(){ 
var tileImg = new Array(); 
for(var i=0;i<tiles.length;i++){ 
    tileImg[i] = new Image(); 
    tileImg[i].src = tiles[i]; 
    tileImg[i].onload = function(){ 
     loaded++; 
    } 
    } 
} 

function loadall(){ 
if(loaded == tiles.length){ 
    clearInterval(loadTimer); 
    loadTimer = setInterval(gameUpdate,100); 
} 
} 

function gameUpdate(){ 
ctx.clearRect(0,0,canvas.width,canvas.height); //line 32 
draw(); 
} 

function init(){ 
canvas = document.getElementById("canvas"); 
ctx = canvas.getContext("2d"); 
loadimg(); 
loadTimer = setInterval(loadall,100); 
} 
+0

嗯,我從解剖另一個腳本得到我的腳本: http://glacialflame.com/tutorials/tiles/02/ 他的腳本在init函數中有ctx,但不會產生相同的未定義錯誤。所以我很困惑。他有什麼不同? – Sir 2012-02-25 23:00:24

+1

該頁面上的腳本不包含** var **關鍵字。在Javascript中,如果你沒有使用** var **定義一個變量,它將被自動聲明爲全局變量(即將它放在代碼的頂部)。 – DNJohnson 2012-02-25 23:09:32

+0

感謝您解釋:)我現在明白了! – Sir 2012-02-25 23:13:38

2

當你初始化函數中定義ctxctx將是私有的該功能,因此不提供線32停止執行ctx,因爲它是內不可gameupdate(),所以你沒有得到關於canvas(尚未!)的錯誤。如果通過在init函數之外聲明ctx,所有函數都可以使用ctx,那麼您的錯誤將移至canvas變量(因爲它對init函數也是私有的),說明canvas未聲明。

要使變量對所有函數都可用,請在函數外部的腳本頂部執行聲明。然後從你刪除var關鍵字的init功能和簡單的分配變量來代替:

var ctx, canvas; 

// ... all your functions 

function init(){ 
    canvas = document.getElementById("canvas"); 
    ctx = canvas.getContext("2d"); 
    loadimg(); 
    loadTimer = setInterval(loadall,100); 
} 

有關在JavaScript中的變量範圍的更多信息,看看這個MDN article

+0

星爺,但如果你看到我在DJohnson的帖子的鏈接評論上發佈的鏈接的網頁源代碼有它在init函數中= /但不會產生相同的問題。 – Sir 2012-02-25 23:03:52

+0

@Dave當他聲明他的變量時,他省略了'var'關鍵字,那麼這個變量就不會變成私有的,它會在全局名稱空間中結束,從而變得可用於所有函數。這通常被認爲是不好的做法,因爲它會污染全局名稱空間,並且存在這樣的風險,即它可能會干擾同一頁面上的其他腳本,使用相同的變量名稱。如果您想了解更多關於JavaScript的信息,可以在Google上使用JavaScript命名空間。 – 2012-02-25 23:09:38

+0

哦,我看到了 - 感謝您的解釋! :) – Sir 2012-02-25 23:13:30

2

我只能猜測,但爲了這個工作:

var canvas = document.getElementById("canvas"); 
var ctx = canvas.getContext("2d"); 

你需要有一個

<canvas id="canvas"></canvas> 

元素在你的HTML。

否則,getElementById("canvas")將不會返回畫布,而canvas.getContext("2d");將不會設置ctx var。

編輯:另請參閱DJohnson的帖子關於您的畫布和ctx變量的範圍。

如果您省略了var關鍵字,則變量的範圍將是全局的。 看到:Javascript variable scope

在你的樣品,你在本地使用

function init(){ 
    var ctx = canvas.getContext("2d"); 
} 

這就是爲什麼你不能在另一個函數訪問它定義它(這也是什麼是從您發佈的參考值不同)。

所以這會工作:

function init(){ 
    ctx = canvas.getContext("2d"); // not var keyword 
} 

,這將是正確的:

var ctx; 

function init(){ 
    ctx = canvas.getContext("2d"); 
} 
+0

我的畫布是我的html頁面: <身體的onLoad = 「的init();」> \t <帆布ID = 「畫布」 WIDTH = 「1200像素」 高度= 「600px的」 class =「canvas」>您的瀏覽器不支持HTML5畫布。 – Sir 2012-02-25 23:04:38