【问题标题】:Why doesn't this Javascript image object get added to the image array?为什么不将此 Javascript 图像对象添加到图像数组中?
【发布时间】:2013-07-13 14:18:34
【问题描述】:

我一直在尝试创建一个基于 HTML5 的小型示例,但遇到了一些问题。我想在<canvas> 上渲染一块石头,但是这个 Javascript 对象不能正常工作。

function ImageData() {
    this.image_names = ["rock1"];
    this.images = new Array();
    this.loadResources = function () {
        for (var i = 0; i < this.image_names.length; i++) {
            var img = new Image();
            img.onload = (function (a) {
                a.images[a.image_names[i]] = img;
                console.log(a.images); //log is successful, image is in array
            })(this);
            img.src = "images/" + this.image_names[i] + ".png";
        }
    }
}

它的用途如下:

var a = new ImageData();
a.loadResources();
var rock1_image = a.images["rock1"]; //the "rock1.png" image

如果您尝试通过控制台访问该对象,在确定图像已加载后,您会看到图像数组中没有图像。我不知道为什么它不起作用。看了好几遍了。

编辑:这是我的最终工作结果:

function ImageData() {
    this.image_names = ["rock1"];
    this.images = new Array();
    this.loadResources = function (callback) {
        for (var i = 0; i < this.image_names.length; i++) {
            var img = new Image();
            img.onload = (function (a, i) {
                return function() {
                    a.images[a.image_names[i]] = img;
                    if (i == (a.image_names.length - 1)) callback();
                };
            })(this, i);
            img.src = "images/" + this.image_names[i] + ".png";
        }
    }
}

【问题讨论】:

  • onload属性赋值的RHS上的函数立即运行,所以结果被赋值。它不返回任何内容,因此分配了 undefined
  • 如果您使用非数字键,为什么images 是一个数组。
  • 在处理即时生成的多个帧中的多个对象时,无论它们是如何组织的,都更容易从数组中提取图像。一张图片被使用了几次。

标签: javascript html image canvas


【解决方案1】:

我敢说您在将它添加到您的阵列之前尝试访问它。我建议在您的 loadResources 方法中添加回调或其他内容,以确保在您尝试访问它之前它就在那里。

this.loadResources = function (callback) {
    for (var i = 0; i < this.image_names.length; i++) {
        var img = new Image();
        img.onload = (function (a, i) {
            return function() {
                a.images[a.image_names[i]] = img;
                console.log(a.images); //log is successful, image is in array
                callback();
            };
        })(this, i);
        img.src = "images/" + this.image_names[i] + ".png";
    }
} 

然后

var a = new ImageData();
var rock1_image;
a.loadResources(function() {
    rock1_image = a.images["rock1"];
    // do whatever you need to do with the image in here.
});

另外,@Igor 提到的。我完全错过了。我调整了上面的代码,这样您就可以保留您的 this 范围,而无需在其他地方设置它。

已更新以解决 @RobD 提出的 i 问题。

【讨论】:

  • this 与作用域无关,它只是一个由调用设置的变量,始终在当前执行上下文中解析。
  • 另外,从 onload 函数到外部 loadResources 函数之间有一个带有 i 的闭包,这会在以后引起问题。
【解决方案2】:

onload 处理程序定义之后删除(this)。您实际上是立即调用此函数,将 undefined(因为它什么都不返回)分配为 img.onload 值。

【讨论】:

  • this 是必需的,它引用了 IIFE 中的实例 (a)。
  • @RobG 那么也许 IIFE 应该返回一个函数?
  • @JanDvorak—不知道,它还不如将主体作为 for 块中的语句运行,无需将 this 传递给函数。 OP似乎不需要将任何东西分配给onload。 Kalley 允许回调,所以工作完成了。
【解决方案3】:

在代码中:

> function ImageData() {
>     this.image_names = ["rock1"];
>     this.images = new Array();
>     this.loadResources = function () {
>         for (var i = 0; i < this.image_names.length; i++) {
>             var img = new Image();
>             img.onload = (function (a) {

这个函数会立即运行并且不返回值,所以undefined会被赋值。因此,分配没有意义,只需运行代码即可。

>                 a.images[a.image_names[i]] = img;

Images 是一个用作普通对象的数组。那么最好使用普通对象。

>                 console.log(a.images); //log is successful, image is in array
>             })(this);

外部的this因为IIFE所以必须传入。移除 IIFE 并且不需要通过 this。如果对实例的引用存储在函数中,那么函数的调用方式就无关紧要(即您不必在调用中设置 this)。

>             img.src = "images/" + this.image_names[i] + ".png";
>         }
>     }
> }

你可能想要这样的东西:

function ImageData() {
    this.image_names = ['rock1'];
    this.images = {};
    imageData = this;
    this.loadResources = function (callback) {

        for (var i = 0; i < imageData.image_names.length; i++) {
            var img = new Image();
            imageData.images[a.image_names[i]] = img;
            img.src = 'images/' + this.image_names[i] + '.png';

            if (callback) {
                img.onload = callback;
            }
        }
    }
}

var a = new ImageData();
a.loadResources(function(){console.log('loaded: ' + this.src);}); // loaded: …

window.onload = function() {
    document.body.appendChild(a.images.rock1); // image appears in document
}

【讨论】:

    【解决方案4】:

    我还没有测试你的代码,但我想这是问题所在: 您正在尝试在加载之前访问您的图像。您可以在加载后使用回调事件处理程序:

    var data = new ImageData();
    
    data.loadResources(function(imgObj){
     // imgObj is the newly load image here. Have fun with it now!
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-01
      • 2020-09-10
      • 2021-08-10
      • 2018-11-20
      • 2022-01-12
      • 1970-01-01
      • 2020-03-07
      相关资源
      最近更新 更多