Where does an anonymous function gets its arguments
我正在学习借助一本书来开发Windows 8风格的应用程序。 我正在阅读的这一章重点介绍用于开发的HTML,CSS和JavaScript语言。 应用程序在ListView中显示"我的图片"文件夹中的图像,并在用户单击或点击图像时将其删除。 以下是在ListView中实现删除图像的代码:
1 2 3 4 5 6 7 8 9 10 11 | 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(); }); }); }); |
我的问题是,
它很简单:无论函数内部调用哪个回调传递参数。请参阅addEventListener告诉执行的Javascript引擎在事件发生时调用您指定的回调函数。 javascript引擎将您的匿名函数保存在某个变量中 - 稍后可以使用该确切变量调用它,并传递任意数量的参数。
为了说明这一点,请考虑这样的事情,即处理事件的内部功能(简单虚构,只是为了说明如何完成):
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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是一种所谓的"函数式语言",函数只是变量的值。
1 | function someFunc () {} |
实际上只是某种捷径(技术上它不是,但它做同样的事情)
1 | var someFunc = function () {} |
这就是说,可以将多个名称与一个函数关联起来:
1 2 3 4 | var someFunc = function () {} var sameFunc = someFunc; var stillSame = somefunc; var alsoSame = stillSame; |
你可以使用任何这些名称调用该函数,包括传递参数:
1 2 3 | var someFunc = function (arg) { alert(arg); } var sameFunc = someFunc; sameFunc("It worx"); |
你甚至可以在没有命名的情况下调用函数:
1 | (function () {alert("test")})();< |
要么
1 | (function (arg) { alert(arg); })("test") |
使用这个概念进行变换最终导致(很长的路要走)像y-combinator这样的东西。
你需要理解这段代码的是重写一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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); |
这段代码的工作原理是一样的,但是很明显
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // 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 } |
事件侦听器收到的参数是从
有关如何创建和分派事件,请参阅此文档。事件对象的结构可以变化,以将信息传递给事件处理程序以执行必要的步骤。因此,在您执行
请记住,可以有多个事件处理程序监听事件,因此浏览器为事件顺序器维护一个堆栈,顺序运行它们,每个事件都传递
匿名函数与命名函数没有区别。在JavaScript函数中,第一类对象意味着常规对象。所以你可以像常规对象(数字,字符串)一样传递它们,而不必命名它们。唯一的问题是重用成为一个问题。
Event handlers may be attached to various objects including DOM
elements, document, the window object, etc. When an event occurs, an
event object is created and passed sequentially to the event
listeners.
资料来源:https://developer.mozilla.org/en-US/docs/Web/API/Event
事件监听器或事件处理程序可以是匿名函数或命名函数,它确实无关紧要。关键是它是事件接口,它定义了传递给处理程序的事件对象。
要从您正在使用的事件中找到确切的事件属性,请参阅Windows文档:http://msdn.microsoft.com/en-us/library/windows/apps/br211827.aspx
它是一个CustomEvent,所有过程都是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //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); |
作为侦听器传递的所有函数都是基于键存储的,例如:
1 2 3 4 | var observers = { "iteminvoked" : [f1, f2], //other keys } |
它与没有名称没有任何关系,函数对象存储在某种数组中。并且
1 2 3 4 5 6 7 8 9 10 | 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; } } |
正如你所看到的那样,它是