Функция не выполняется при создании объектов в цикле - JavaScript
В следующем коде drawFunc не выполняется во время цикла (я вижу, что при пошаговой отладке код просто переходит в конец функции).
Функция выполняется в строке "stage.add(layer);", вызывая ошибку.
Любая помощь о том, как это исправить?
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
canvas {
border: 1px solid #9C9898;
}
</style>
<script type="text/javascript" src="http://www.html5canvastutorials.com/libraries/kinetic-v3.9.7.js"></script>
<script>
window.onload = function() {
// global parameters
var curvatureX = 10;
var curvatureY = 10;
var nodeRadius = 10;
var stage = new Kinetic.Stage({
container: "container",
width: 578,
height: 300
});
var layer = new Kinetic.Layer();
var nodes = [];
for (var i = 0;i<10;i++){
nodes[i] = new Kinetic.Circle({
x: i*20,
y: i*5,
z:1,
radius: nodeRadius,
fill: "blue",
stroke: "black",
strokeWidth: 4
});
layer.add(nodes[i]);
}
var edges = [];
for (var i = 0;i<9;i++){
console.log("just after the for: "+i);
edges[i]= new Kinetic.Shape({
// *** PROBLEMS IS HERE
// *** FOR LOOP SKIPS THE FOLLOWING LINES
drawFunc: function() {
var context = this.getContext();
context.beginPath();
console.log("in the drawing function: "+i);
context.moveTo(nodes[i].getX(), nodes[i].getY());
if ((nodes[i].getY()-nodes[i+1].getY())<0){
context.quadraticCurveTo((nodes[i].getX()+nodes[i+1].getX()+curvatureX)/2, (nodes[i].getY()+nodes[i+1].getY()-curvatureY)/2, nodes[i+1].getX(), nodes[i+1].getY());
}
else{
context.quadraticCurveTo((nodes[i].getX()+nodes[i+1].getX()+curvatureX)/2, (nodes[i].getY()+nodes[i+1].getY()+curvatureY)/2, nodes[i+1].getX(), nodes[i+1].getY());
}
context.lineWidth = 10;
// line color
context.strokeStyle = "black";
context.stroke();
},
// *** LOOP RESUMES HERE
fill: "#00D2FF",
stroke: "black",
strokeWidth: 4
});
layer.add(edges[i]);
}
//*** FUNCTION IS EXECUTED HERE, CAUSING BUG.
stage.add(layer);
var amplitude_1 = 100;
var amplitude_2 = 30;
var period = 2000;
// in ms
var centerX = stage.getWidth() / 2;
var centerY = stage.getHeight() / 2;
stage.onFrame(function(frame) {
for (var i=0;i<nodes.length;i++){
nodes[i].setX(amplitude_1 * i * Math.sin(frame.time * 2 * Math.PI / period) + centerX);
nodes[i].setY(amplitude_2 * i+ 20);
}
layer.draw();
});
stage.start();
};
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
1 ответ
Вы не можете использовать переменную, объявленную вне функции, и предполагать, что ее значение при использовании внутри этой функции соответствует значению, которое было в момент объявления функции.
В частном случае переменной цикла этой переменной будет присвоено последнее значение к моменту вызова внутренней функции.
Чтобы это исправить, вы должны "закрыть" значение внешней переменной внутри новой области видимости, в вашем случае это будет выглядеть так:
for (var i = 0; i < 9; ++i) {
...
drawFunc: (function(i) { // <------------+
return function() { // |
alert(i); // you can use this "i" here
}
})(i)
}
Необычно выглядящая конструкция, теперь есть выражение для немедленного вызова функции, которое было передано вашей переменной цикла i
, но теперь имеет локально связанную копию этой переменной в своей области видимости.