我正在学习借助一本书来开发Windows 8风格的应用程序。我正在阅读的这一章重点介绍用于开发的HTML,CSS和JavaScript语言。应用程序在 ListView 中显示“我的图片”文件夹中的图像,并在用户单击或点击图像时将其删除。以下是在 ListView 中实现删除图像的代码:
var lv = document.getElementById('lv');
lv.addEventListener('iteminvoked', function (eventObj) {
eventObj.detail.itemPromise.then(function (listViewItem) {
var binding = files.dataSource.createListBinding();
binding.fromIndex(listViewItem.index).then(function (dataItem) {
var key = dataItem.key;
files.dataSource.remove(key);
binding.release();
});
});
});
我的问题是,eventObj
方法中匿名函数的addEventListener
参数在哪里得到它的值?我在这里问了一个类似的问题:Passing arguments in anonymous functions in JavaScript,但我无法完全理解它。我在MSDN上搜索了addEventListener
的文档,但它只是说它需要一个事件处理函数,但它没有说明参数。提前谢谢。
答案 0 :(得分:2)
这很简单:无论函数内部调用哪个回调传递参数。请参阅addEventListener告诉执行的Javascript引擎在事件发生时调用您指定的回调函数。 javascript引擎将你的匿名函数保存在某个变量中 - 稍后可以使用该确切变量调用它,传递任意数量的参数。
为了说明这一点,请考虑这样的事情,即处理事件的内部函数(简单地虚构,只是为了说明如何完成):
var callbacks = [];
function addEventListener(newEvent, newCallback) {
callbacks.push({event : newEvent, callback : newCallback});
}
function handleEvent (someEvent) {
for (var i = 0 ; i < callbacks.length ; i++ ) {
if (callbacks[i].event == someEvent.name) {
callbacks[i].callback(someEvent);
}
}
}
更多解释:
由于javascript是一种所谓的“函数式语言”,函数只是变量的值。
function someFunc () {}
实际上只是某种捷径(技术上不是,但它做同样的事情)
var someFunc = function () {}
这就是说,可以将多个名称与一个函数相关联:
var someFunc = function () {}
var sameFunc = someFunc;
var stillSame = somefunc;
var alsoSame = stillSame;
你可以使用任何这些名称调用该函数,包括传递参数:
var someFunc = function (arg) { alert(arg); }
var sameFunc = someFunc;
sameFunc("It worx");
你甚至可以在没有命名的情况下调用函数:
(function () {alert("test")})();<
或
(function (arg) { alert(arg); })("test")
使用这个概念进行变换最终导致(很长的路要走)像y-combinator这样的事情。
答案 1 :(得分:1)
它是一个CustomEvent,所有过程都是这样的:
//you add a anonymous function to a specific listener
lv.addEventListener('iteminvoked', function (eventObj) {
console.log(eventObj===myEvent);
});
//somewhere in your code a CustomEvent gets created based on "iteminvoked" key
var myEvent = new CustomEvent("iteminvoked", {
itemInfo: {
name: "yourItem"
},
bubbles: true,
cancelable: false
});
//somewhere when an item gets invoked this code raise the `iteminvoked` trigger
lv.dispatchEvent(myEvent);
作为侦听器传递的所有函数都是根据键存储的,如:
var observers = {
"iteminvoked" : [f1, f2],
//other keys
}
它与没有名称没有任何关系,函数对象存储在某种数组中。并且dispatchEvent
通过数组并调用所有函数,并传递myEvent
作为参数。它是一个Observer
模式,用javascript实现,我在我自己的javascript库中实现过一次,如:
var lv = /*your element*/;
if(observers["iteminvoked"]){
for(var i=0;i<observables["iteminvoked"].length;i++){
var func = observables["iteminvoked"][i];
var o = func.call(lv, myEvent);
//this line is to support return false
if(o!==undefined && o===false) break;
}
}
你可以看到调用所有观察者的dispatchEvent
resplonsiblity,你的函数无论是否具有名称,都会被lv
作为this
上下文调用{ {1}}作为参数。
答案 2 :(得分:1)
事件处理程序可以附加到包括DOM在内的各种对象 元素,文档,窗口对象等。当事件发生时,一个 创建事件对象并按顺序传递给事件 听众。
来源:https://developer.mozilla.org/en-US/docs/Web/API/Event
事件监听器或事件处理程序可以是匿名函数或命名函数,它确实无关紧要。关键是它是事件接口,它定义了传递给处理程序的事件对象。
要准确了解您所使用事件的事件属性,请参阅Windows文档:http://msdn.microsoft.com/en-us/library/windows/apps/br211827.aspx
答案 3 :(得分:1)
事件监听器收到的参数是从dispatchEvent
发送的,即当事件已发送时,它会将事件对象传递给您的处理程序。
有关如何创建和分派事件的信息,请参阅此documentation。事件对象的结构可以变化,以将信息传递给事件处理程序以执行必要的步骤。因此,在您执行lv.dispatchEvent(newevent)
的情况下,这会向您的事件处理程序发送newevent
eventObj
。
请记住,可以有多个事件处理程序监听事件,因此浏览器为事件顺序器维护一个堆栈,顺序运行它们,每个事件都传递eventObj
。
匿名函数与命名函数没有区别。在JavaScript函数中,第一类对象意味着常规对象。所以你可以像常规对象(数字,字符串)一样传递它们,而不必命名它们。唯一的问题是重用成为一个问题。
答案 4 :(得分:1)
您需要了解此代码的内容是重写一下:
var lv = document.getElementById('lv'),
invokeHandler = function (eventObj) {
var promiseFullfilled = function (listViewItem) {
var binding = files.dataSource.createListBinding(),
anotherPromiseFullfilled = function (dataItem) {
var key = dataItem.key;
files.dataSource.remove(key);
binding.release();
};
binding.fromIndex(listViewItem.index).then(anotherPromiseFullfilled);
};
eventObj.detail.itemPromise.then(promiseFullfilled);
};
lv.addEventListener('iteminvoked', invokeHandler);
此代码的工作原理相同,但很明显,addEventListener
或then
实际上并不知道任何有关它们传递的回调函数。但是,他们可以使用Function.prototype.call
或Function.prototype.apply
来应用参数:
// This is PSEUDOCODE, event model actually works in a totally different way
HTMLElement.prototype.addEventListener = function(eventType, callback, bubbles) {
// callbacks is some internal collection for this specific element, probably available via a closure, looks something like:
// {
// 'someEventType': [callback1, callback2],
// 'someOtherEvent': [callback1, callback3, callback4]
// }
callbacks[eventType].push(callback);
}
// This is called whenever an event is triggered on an element
HTMLElement.prototype.dispatchEvent = function(event) {
callbacks[event.type].forEach( function(callback) {
return callback.call(this, event); // the callback is called with 'this' set to the element DOM object, and 'event' is the first argument
});
// then it can bubble or cancel depending on the event type and callback results
}