2012-02-14 19 views
5

Czy ktoś mógłby mi to wyjaśnić?Wydaje się, że używam zmiennej przed jej pełnym utworzeniem w JavaScript, ale to działa - dlaczego?

var diagramImage = new Kinetic.Shape(function() { 
    var context = this.getContext(); 
    context.beginPath(); 
    context.lineWidth = 1; 
    //This is crazy tricks. It's part of the KineticJS demo website, but how am I able to assign diagramImage.color here? 
    context.strokeStyle = diagramImage.color; 

    var lastVertice = polygon.Vertices[polygon.Vertices.length - 1]; 

    context.moveTo(lastVertice.X, lastVertice.Y); 

    for (var i = 0; i < polygon.Vertices.length; i++) { 
     var vertice = polygon.Vertices[i]; 
     context.lineTo(vertice.X, vertice.Y); 
    } 

    context.stroke(); 
    context.closePath(); 
}); 

Wydaje mi się, że nie istnieje diagramImage aż kinetycznej powraca konstruktora, ale jestem w stanie (i wydaje się konieczne) przypisać strokeStyle do diagramImage „s kolor kontekst jest - przed diagramImage został stworzony? Dlaczego to działa?

EDIT: Pełny kod:

function DrawPolygon(diagramLayer, polygon) { 
    var diagramImage = new Kinetic.Shape(function() { 
     var context = this.getContext(); 
     context.beginPath(); 
     context.lineWidth = 2; 
     //This is crazy tricks. It's part of the KineticJS demo website, but how am I able to assign diagramImage.color here? 
     context.strokeStyle = diagramImage.color; 

     var lastVertice = polygon.Vertices[polygon.Vertices.length - 1]; 

     context.moveTo(lastVertice.X, lastVertice.Y); 

     for (var i = 0; i < polygon.Vertices.length; i++) { 
      var vertice = polygon.Vertices[i]; 
      context.lineTo(vertice.X, vertice.Y); 
     } 

     context.stroke(); 
     context.closePath(); 
    }); 

    diagramImage.color = "red"; 

    diagramImage.on("mouseover", function() { 
     this.color = "green"; 
     diagramLayer.draw(); 
    }); 

    diagramImage.on("mouseout", function() { 
     this.color = "red"; 
     diagramLayer.draw(); 
    }); 

    diagramLayer.add(diagramImage); 
    planViewStage.add(diagramLayer); 
} 
+0

Czy "diagramImage" jest już zdefiniowany przed tą częścią kodu, który zawiera? – ziesemer

+0

Nie. Zobacz ten samouczek: http://www.html5canvastutorials.com/labs/html5-canvas-interactive-flower/ Robią to samo ze zmienną "center" –

+0

Czy masz dodatkowy kod, który możesz opublikować, to dowodzi twoje twierdzenia? – shanabus

Odpowiedz

8

Bo gdzie dzwonisz diagramImage.color jest w obrębie zamknięcia/funkcji, która jest przekazywana do konstruktora Kinetic.Shape. Ta funkcja nie jest wywoływana/nie jest wykonywana przez konstruktor, dopóki nowa instancja utworzona przez konstruktora nie zostanie przypisana do diagramImage.

Oto minimalny przykład, który może lepiej wyjaśnić, co się dzieje:

var MyObject = function(f){ 
    this.myFunc = f; // f is executed sometime later... 
}; 
MyObject.prototype.execute = function(){ 
    this.myFunc(); 
}; 

var myObjInst = new MyObject(function(){ 
    console.log("myObjInst:", myObjInst); 
}); 
myObjInst.execute(); 

Jak zauważył Twisol, to można poprawić za pomocą this zamiast. Na przykład:

(function(){ 
    var MyObject = function(f){ 
    this.myFunc = f; // f is executed sometime later... 
    }; 
    MyObject.prototype.execute = function(){ 
    this.myFunc(); 
    }; 

    var myObjInst = new MyObject(function(){ 
    console.log("myObjInst:", this); 
    }); 
    myObjInst.execute(); 
})(); 

Jednakże, jak zauważył Chris, chyba że udokumentowane API - nie ma gwarancji, że this skieruje do Kinetic.Shape podczas zwrotnego - więc nadal używać diagramImage tutaj może być jeszcze lepszy z tych 2 opcje.

Podsumowując, uważam, że nie jest to najlepsze API/przykład/użycie JavaScriptu - i nie uważam tego za niuans kodu JavaScript, z którym należy się uporać. Jasne, te niuanse są tam, jeśli ich potrzebujesz - ale nie musisz.

+0

Czy jest jakiś sposób, abym uczynił ten kod bardziej ... intuicyjnym? Czy jest to niuans JavaScript, który będę musiał nauczyć się kochać? :) –

+0

Źródło (dosłownie) [tutaj] (http://www.kineticjs.com/download/kinetic-v3.7.3.js). 'drawFunc' nie jest nazywany ani w' Kinetic.Shape' ani 'Kinetic.Node', ale fakt, że nazywa się' drawFunc' i jest przechowywany jako własność, mówi. – Twisol

+1

@SeanAnderson: Tak, użyj 'this' w funkcji zamiast' diagramImage'. To jest w porządku, ponieważ tutaj, gdzie 'drawFunc' * jest nazywany *, zapewnia właściwy obiekt jako' this'. – Twisol

0

myślę, że to stanowisko może pomóc wyjaśnić - http://www.quirksmode.org/js/associative.html

Szczególnie odcinek na asocjacyjnych. Zapis wyjaśnia, że ​​obiekty w javascriptu są również uważane za tablice asocjacyjne.

Zdarzenie, chociaż diagramImage.strokeStyle może nie być jednoznacznie zdefiniowane, nadal można odwoływać się do diagramImage['strokeStyle'].

Czy to pomaga?

1

To interesująca konstrukcja. Wygląda na to, że:

  • diagramImage jest odniesieniem przed przypisaniem czegokolwiek tylko na podstawie oświadczenia. Aby to sobie wyobrazić, wyobraź sobie, że var diagramImage był w poprzedniej linii przez swój własny.
  • Kinetic.Shape przyjmuje wywołanie zwrotne, tę anonimową funkcję, jako jeden z argumentów konstruktora do późniejszego wykorzystania.
  • Oddzwonienie dotyczy obiektu Kinetic.Shape. Przypuszczalnie istnieje pewna umowa, która opisuje, do czego odnosi się później (o czym świadczy użycie this.getContext()) i nie jest to obiekt Kinetic.Shape.
  • Ponieważ diagramImage jest odniesieniem, a do czasu, kiedy odniesienie zostanie użyte, zostanie mu przypisane nowe Kinetic.Shape, jest to koszerne, aby użyć go do tego celu.

Zasadniczo nie różni się to od zwykłego wzorca użycia zmiennej lokalnej, aby udostępnić ją jako wywołanie zwrotne, np.

var self = this; 
$('myelement').click(function(){ self.hi = true; }); 

Tyle, że tutaj, zmienna zostanie udostępniona na później nie jest obecny obiekt, jest członkiem wspomnianego obiektu.

+0

http://en.wikipedia.org/wiki/Closure_(computer_science) –

Powiązane problemy