在for循环中注释为:
//迭代数组并将每个元素追加为li
...如果我放的话,有一个关闭工作正常 的console.log(标签[X]); 这表明封闭按预期工作。但是,当我把闭包应该包含的实际代码,即。 this.displayImg(标签[X]);它会抛出一个错误。当我点击li时,我得到:
Uncaught TypeError: this.displayImg is not a function
(anonymous function) @ script.js:49
请告知我如何从那个地方访问this.displayImg。
var myGallery = (function () {
var s;
return {
settings: {
data: JSON.parse(data),
filter: document.getElementById("filter"),
gallery: document.getElementById("gallery")
},
init: function () {
// kick things off
s = this.settings;
// By default, call the fillImages function with 'all' tag
this.createFilters("all");
},
createFilters: function (tag) {
// Load the image data
// I made imgs global as I couldn't access it from displayImg
imgs = this.settings.data.images;
// Get image tags and generate a tag array
var tags = ["all"];
for (var i = 0; i < Object.keys(imgs).length; i++) {
// Check if a tag is already in tags
if (tags.indexOf(imgs[i].tag) > -1) {
// Yes, it is, so don't add it
} else {
// No, it isn't, so add it to 'tags'
tags.push(imgs[i].tag);
}
}
// Create an unordered list, assign a class to it and append to filter
var ul = document.createElement('ul');
ul.classList.add("ul-bare");
this.settings.filter.appendChild(ul);
// Iterate over the array and append each element as li
for (var i = 0; i < tags.length; i++) {
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML = tags[i];
li.onclick = (function (x) {
return function () {
console.log(tags[x]);
this.displayImg(tags[x]);
};
})(i);
}
},
displayImg: function (filter) {
// Add images to #gallery
for (var i = 0; i < Object.keys(imgs).length; i++) {
var div = document.createElement("img");
// If the tage is 'all', display all images
if (filter === "all") {
div.src = imgs[i].src;
this.settings.gallery.appendChild(div);
} else {
// Display only images of certain category (tag argument)
if (imgs[i].tag === filter) {
div.src = imgs[i].src;
this.settings.gallery.appendChild(div);
}
}
}
}
};
})();
myGallery.init();
谢谢
答案 0 :(得分:5)
在onclick
内,this
将是对点击的DOM元素的引用,而不是this
表示您将其挂钩的位置。
如果要在设置处理程序时访问对象this
,请使用变量:
var thisObj = this;
for (...) {
...然后在处理程序中:
thisObj.displayImg(tags[x]);
虽然在这种情况下,由于您不需要this
来引用处理程序,因此您可以使用Function#bind
使其更简单:
for (var i = 0; i < tags.length; i++) {
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML = tags[i];
li.onclick = function(x) {
console.log(tags[x]);
this.displayImg(tags[x]);
}.bind(this, i);
}
Function#bind
返回一个新函数,在调用时,将调用具有特定this
值的原始函数以及您给出的任何其他参数bind
(后跟在运行时接收的任何参数) )。
旁注:你也可以只传入标签,而不是索引:
var thisObj = this;
for (var i = 0; i < tags.length; i++) {
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML = tags[i];
li.onclick = (function(tag) {
return function() {
console.log(tag);
thisObj.displayImg(tag);
};
})(tags[i]);
}
或
for (var i = 0; i < tags.length; i++) {
var li = document.createElement('li');
ul.appendChild(li);
li.innerHTML = tags[i];
li.onclick = function(tag) {
console.log(tag);
this.displayImg(tag);
}.bind(this, tags[i]);
}
答案 1 :(得分:2)
内部处理程序this
引用DOM元素。我会使用bind,它也是传递i
的价值的更具可读性的解决方案:
li.onclick = function(x) {
console.log(tags[x]);
this.displayImg(tags[x]);
}.bind(this, i);