Ответ 1
Все остальные ответы являются некой версией "сделай замыкание". ОК, это работает. Я думаю, что замыкания - это круто, а языки, которые их поддерживают - это круто...
Тем не менее, есть гораздо более чистый способ сделать это, ИМО. Просто используйте объект изображения для хранения того, что вам нужно, и обращайтесь к нему в обработчике загрузки через "this
":
imageObj = new Image();
imageObj.x = 1;
imageObj.y = 2;
imageObj.onload = function() {
context.drawImage(this, this.x, this.y);
};
imageObj.src = ".....";
Это очень общий метод, и я постоянно использую его во многих объектах в DOM. (Я особенно использую его, когда у меня есть, скажем, четыре кнопки, и я хочу, чтобы все они совместно использовали обработчик "onclick"; у меня есть обработчик, который вытаскивает немного пользовательских данных из кнопки, чтобы выполнить определенное действие кнопки THAT.)
Одно предупреждение: вы должны быть осторожны, чтобы не использовать свойство объекта, которое сам класс объекта имеет особое значение или использовать. (Например: вы не можете использовать imageObj.src
для какого-либо старого пользовательского использования; вы должны оставить его для исходного URL.) Но как в общем случае узнать, как данный объект использует все его свойства? Строго говоря, вы не можете. Чтобы сделать этот подход максимально безопасным:
- Оберните все свои пользовательские данные в один объект
- Присвойте этот объект свойству, которое необычно/вряд ли будет использоваться самим объектом.
В связи с этим использование "x" и "y" немного рискованно, поскольку некоторые реализации Javascript в некоторых браузерах могут использовать эти свойства при работе с объектом Image. Но это, вероятно, безопасно:
imageObj = new Image();
imageObj.myCustomData = {x: 1, y: 2};
imageObj.onload = function() {
context.drawImage(this, this.myCustomData.x, this.myCustomData.y);
};
imageObj.src = ".....";
Еще одно преимущество этого подхода: он может сэкономить много памяти, если вы создаете много заданного объекта - потому что теперь вы можете совместно использовать один экземпляр обработчика загрузки. Учтите это, используя замыкания:
// closure based solution -- creates 1000 anonymous functions for "onload"
for (var i=0; i<1000; i++) {
var imageObj = new Image();
var x = i*20;
var y = i*10;
imageObj.onload = function() {
context.drawImage(imageObj, x, y);
};
imageObj.src = ".....";
}
Сравните с функцией разделяемой загрузки, ваши пользовательские данные спрятаны в объекте Image:
// custom data in the object -- creates A SINGLE "onload" function
function myImageOnload () {
context.drawImage(this, this.myCustomData.x, this.myCustomData.y);
}
for (var i=0; i<1000; i++) {
imageObj = new Image();
imageObj.myCustomData = {x: i*20, y: i*10};
imageObj.onload = myImageOnload;
imageObj.src = ".....";
}
Много памяти сохранено и может работать быстрее, так как вы не создаете все эти анонимные функции. (В этом примере функция onload является однострочной.... но у меня были функции загрузки из 100 строк, и 1000 из них, безусловно, считались бы расходующими много памяти без веской причины.)
ОБНОВЛЕНИЕ: см. использование атрибута [data- * ' для стандартного (и "одобренного стандартами") способа сделать это вместо моего специального предложения использовать myCustomData
.