5

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

3 回答 3

8

因为您调用diagramImage.color的位置是在传递给Kinetic.Shape构造函数的闭包/函数中。在将构造函数创建的新实例分配给 之前,构造函数不会调用此函数/不会执行此函数diagramImage

这是一个可以更好地解释正在发生的事情的最小示例:

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

正如 Twisol 所指出的,这可以通过使用this来改进。例如:

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

然而,正如 Chris 所指出的,除非 API 记录了 - 不能保证在回调期间this会引用Kinetic.Shape- 所以继续在diagramImage这里使用可能仍然是这两个选项中更好的选择。

简而言之,我认为这不是 JavaScript 的最佳 API/示例/使用 - 我不会认为这是您应该处理的 JavaScript 的细微差别。当然,如果您需要,这些细微差别就在那里 - 但您不必这样做。

于 2012-02-14T17:04:41.703 回答
1

这是一个有趣的结构。发生的事情似乎是:

  • diagramImage是在仅仅凭借声明分配任何东西之前的引用。为了形象化这一点,想象一下它var diagramImage本身就在前一行。
  • Kinetic.Shape将回调(该匿名函数)作为稍后使用的构造函数参数之一。
  • 回调想要引用该Kinetic.Shape对象。大概有一些契约描述了this后来所指的东西(如this.getContext()使用所证明的那样),它不是Kinetic.Shape对象。
  • 因为diagramImage是一个参考,并且在使用参考时,它已经被分配了新Kinetic.Shape的,将它用于上述目的是符合规定的。

原则上,这与使用局部变量使当前 this 在回调中可用的通常模式没有什么不同,例如

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

只是在这里,稍后可供使用的变量不是当前对象,而是所述对象的成员。

于 2012-02-14T17:50:26.360 回答
0

我认为这篇文章可能有助于解释它 - http://www.quirksmode.org/js/associative.html

特别是关于关联数组的部分。该文章解释说,javascript中的对象也被视为关联数组。

所以事件虽然diagramImage.strokeStyle可能没有明确定义,但您仍然可以引用diagramImage['strokeStyle'].

这有帮助吗?

于 2012-02-14T17:06:52.470 回答