当我在事件处理程序中引用对象的参数时,即使将参数设置为对象,该参数也始终为 null

When I reference a parameter of an object inside of an event handler, the parameter is always null even when it's set to an object

这是我的第一个 Stack Overflow 问题,因为我通常会在 google 上找到答案,所以请耐心等待...

我正在从事一个涉及对 canvas 元素进行大量操作的项目。为此,我导入并使用了 jQuery 和 jCanvas。我也在 E​​CMAScript 6 中编写代码。为了更简单的日志记录方法,我使用了 loglevel(因此 "log.debug" 和 "log.info" 等,而不是 "console.log")。

目前,我的问题是事件处理程序与我用来存储每个 canvas 数据的对象有一些奇怪的交互。基本上,在我的 mousedown 和 mousemove 处理程序中,我使用 getCanvasData 函数检索某个 canvas 的数据对象,我显然成功检索了它,但是当我访问 "dragged" 参数时,它总是无效的。在代码的其他部分,我成功将该值更改为一个对象,但每当事件处理程序访问它时,无论如何它仍然为 null。我已经通过为 属性 制作一个 getter 和 setter 来测试它是否真的为 null,当它改变时打印出它的状态(我在最后提供了那段代码,它是替换 getCanvasData 函数中的 'data' 赋值)。

如果您想查看当前形式的完整代码,可以view my project where I'm currently hosting it。这是一个实时版本,这意味着它与我的工作环境同步。当我在家里修改一些东西时,它会更新网站(所以如果你来自未来 - 它可能已经关闭或完全不同)。

在网站上,移动处理程序应该负责在您生成一个 wire/connector 时移动它的一端(通过单击其中一个输入或输出)。由于处理程序无法检索 'dragged',电线永远不会跟随鼠标。但是,当您单击另一个 input/output(请记住,输入仅连接到输出,反之亦然)时,它将连接它们之间的线路 - 该操作是通过访问 'dragged' 属性('dragged' 是对电线本身的引用)并对其执行操作。由于您可以连接电线,这意味着 'dragged' 在处理程序外部成功引用,但在处理程序内部未成功引用。

getCanvasData() 函数:

var canvasData = []; // (among other declarations)

function getCanvasData(canvas) {
    var data, i, tmp;
    // Retrieve the stored data
    for (i = 0; i < canvasData.length; i++) {
        tmp = canvasData[i];
        if (canvas === tmp.canvas) {
            // We got the data for our canvas!
            data = tmp;
            // We no longer need to go through the rest of the list, let's break out of the loop
            break;
        }
    }
    // Check if we got anything back
    if (!data) {
        // No data for this canvas is stored yet. We need to initialize it!
        log.info("New canvas data set is being created. Index: " + canvasData.length);
        data = {
            canvas: canvas, // The canvas this data belongs to
            gates: [],      // An array of all the logic gates on the canvas
            wires: [],      // An array of all the wires on the canvas
            spawners: [],   // An array of all the spawners on the canvas
            dragged: null,  // Currently dragged wire which should follow our mouse
            gateWidth: GATE_WIDTH,  // Width of all logic gates on this canvas
            gateHeight: GATE_HEIGHT // Height of all logic gates on this canvas
        };
        // Store the data in our storage.
        canvasData.push(data);
    }
    return data;
}

部分代码我将不同的处理程序分配给某个 class 的所有 canvases:

var canvasList = $('.logicExercise'), canvas;

/* some code */

// Initialize each canvas
canvasList.each(function (i, obj) {
    canvas = $(this);
    // Initialize the data stored for the canvas
    getCanvasData(canvas);
    // Draw the UI for the canvas
    drawUI(canvas);
    // Assign mouse handlers (for spawning new wires)
    canvas.mousemove(function(event) {
        mouseMoveHandler(event, canvas);
    });
    canvas.mousedown(function(event) {
        mouseDownHandler(event, canvas);
    });
    // Prevent right-click from firing up the context menu when over the canvas
    canvas.bind('contextmenu', function(e){
        e.preventDefault();
        return false;
    });
});

mousedown 和 mousemove 处理程序:

function mouseMoveHandler(event, canvas) {
    var x = event.pageX - canvas.offset().left,
        y = event.pageY - canvas.offset().top,
        data = getCanvasData(canvas);
    if (data.dragged) {    // <--- ALWAYS NULL, AND THEREFORE FAILS
        if (data.dragged.inputs[0].type) {
            data.dragged.outputs[0].x = x;
            data.dragged.outputs[0].y = y;
            data.dragged.updateCoords();
        } else {
            data.dragged.inputs[0].x = x;
            data.dragged.inputs[0].y = y;
            data.dragged.updateCoords();
        }
    }
}

function mouseDownHandler(event, canvas) {
    var data = getCanvasData(canvas);
    if (event.which === 3) {
        // Right click detected!
        if (data.dragged) {    // <--- ALWAYS NULL, AND THEREFORE FAILS
            // We are dragging something! Right click means we need to remove it.
            data.dragged.remove();
            data.dragged = null;
        }
    }
}

我用来检查 'dragged' 状态变化的代码片段:

data = {
    canvas: canvas, // The canvas this data belongs to
    gates: [],      // An array of all the logic gates on the canvas
    wires: [],      // An array of all the wires on the canvas
    spawners: [],   // An array of all the spawners on the canvas
    gateWidth: GATE_WIDTH,  // Width of all logic gates on this canvas
    gateHeight: GATE_HEIGHT,// Height of all logic gates on this canvas
    _dragged: null,
    set dragged(obj) {
        log.info("'dragged' is changing to '" + obj + "'.");
        this._dragged = obj;
    },
    get dragged() {
        log.info("'dragged' is being retrieved when it's '" + this._dragged + "'.");
        return this._dragged;
    }
};

当上面的代码生效时,我得到一个打印输出,通知我 'dragged' 更改为 'Object object',但是当我移动鼠标(触发 mousemove 事件)时,我得到一个打印输出告诉我它是 'null' (甚至不是未定义的)。当我的项目的其他部分使用它时,它成功使用它并实际检索对象。

您应该使用 if (canvas[0] === tmp.canvas[0]) 来引用实际的 canvas 对象,而不是传递给 getCanvasData().

的 jQuery 选择器

当您检查 if (canvas === tmp.canvas) 时,您检查的是 jQuery 选择器,而不是 实际的 canvas 对象。因此,在一个地方你可能传递 $("canvas#foo") 而在其他地方你传递 $("canvas .foo") 它们具有不同的上下文并且不会彼此 ==