Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I seem to be using a variable before it is fully created in Javascript, but this works -- why?

Could someone explain this to me?

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();
});

It seems to me that diagramImage does not exist until the Kinetic constructor returns, but I am able (and seem to need to) assign context's strokeStyle to diagramImage's color -- before diagramImage has been created? Why does this work?

EDIT: Full code:

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);
}
like image 607
Sean Anderson Avatar asked Feb 14 '12 16:02

Sean Anderson


People also ask

Can we use variable without declaring it in JavaScript?

It will throw Reference error : x is not defined, when we assign a value to a variable without declaring it.

What is the correct way to create a variable in JavaScript?

To create a variable in JavaScript, use the let keyword. To be concise, we can combine the variable declaration and assignment into a single line: let message = 'Hello! '; // define the variable and assign the value alert(message); // Hello!

What happens when you assign a variable that hasn't been declared yet in JavaScript?

If you assign a value to a variable that you have not declared with var , JavaScript implicitly declares that variable for you. Note, however, that implicitly declared variables are always created as global variables, even if they are used within the body of a function.

Is it possible to declare a variable type beforehand in JavaScript?

It means a variable must be declared with the data type that specifies the type of data a variable will store. JavaScript is a loosely typed language. It means it does not require a data type to be declared. You can assign any literal values to a variable, e.g., string, integer, float, boolean, etc.


1 Answers

Because where you are calling diagramImage.color is within a closure / function that is passed in to the Kinetic.Shape constructor. This function is not called / is not executed by the constructor until after the new instance created by the constructor is assigned to diagramImage.

Here's a minimal example that may better explain what's happening:

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();

As Twisol noted, this can be improved by using this instead. For example:

(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();
})();

However, as Chris noted, unless documented by the API - there is no guarantee that this will refer to Kinetic.Shape during the callback - so continuing to use diagramImage here may still be the better of these 2 options.

In short, I think this is not the best API / example / use of JavaScript - and I would not consider this a nuance of JavaScript that you should have to deal with. Sure, these nuances are there if you need them - but you don't have to.

like image 180
ziesemer Avatar answered Oct 06 '22 00:10

ziesemer