匿名函数在哪里获取其参数

时间:2014-02-06 08:23:58

标签: javascript windows-8 microsoft-metro winjs windows-applications

我正在学习借助一本书来开发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的文档,但它只是说它需要一个事件处理函数,但它没有说明参数。提前谢谢。

5 个答案:

答案 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);

此代码的工作原理相同,但很明显,addEventListenerthen实际上并不知道任何有关它们传递的回调函数。但是,他们可以使用Function.prototype.callFunction.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
}