如何删除DOM事件处理程序的重复JavaScript代码?

如何删除DOM事件处理程序的重复JavaScript代码?,javascript,dom,javascript-events,readability,Javascript,Dom,Javascript Events,Readability,我正在尝试删除重复的JavaScript代码。我有一个包含许多的页面。每个加载一个图像并执行一些不同的处理。问题是我有许多以下代码的副本: inputFile1.onchange = function (e) { var file = e.target.files[0]; if (typeof file == 'undefined' || file == null) { return; } var image

我正在尝试删除重复的JavaScript代码。我有一个包含许多
的页面。每个加载一个图像并执行一些不同的处理。问题是我有许多以下代码的副本:

inputFile1.onchange = function (e) {
        var file = e.target.files[0];
        if (typeof file == 'undefined' || file == null) {
            return;
        }
        var imageType = /image.*/;
        if (!file.type.match(imageType)) {
            window.alert('Bad file type!');
            return;
        }
        var reader = new FileReader();
        reader.onloadend = function (e) {
            var imageLoader = new Image();
            imageLoader.onload = function () {
                // process image
            };
            imageLoader.src = e.target.result;
        };
        reader.readAsDataURL(file);
    };

inputFile2.onchange = ... (repeats all but process image)
inputFile3.onchange = ... (repeats all but process image)
只有
处理图像
注释处的代码不同。如何删除周围的重复代码


我知道JavaScript函数是对象。如何定义一个函数对象并为每个事件处理程序创建一个不同的实例,为每个对象传递一个不同的
进程映像
函数?

您可以使用闭包为这些函数创建一个生成器,并将单个回调作为参数:

function getChangeHandler(loadCallback) {
    return function (e) {
        var file = e.target.files[0];
        if (typeof file == 'undefined' || file == null) {
            return;
        }
        var imageType = /image.*/;
        if (!file.type.match(imageType)) {
            window.alert('Bad file type!');
            return;
        }
        var reader = new FileReader();
        reader.onloadend = function (e) {
            var imageLoader = new Image();
            imageLoader.onload = loadCallback; // <= uses the closure argument
            imageLoader.src = e.target.result;
        };
        reader.readAsDataURL(file);
    };
}
inputFile1.onchange = getChangeHandler(function() { /* custom process image */ });
inputFile2.onchange = getChangeHandler(function() { /* custom process image */ });
inputFile3.onchange = getChangeHandler(function() { /* custom process image */ });

您可以编写一个返回函数的函数:

function processFile(callback) { //callback is the unique file processing routine
    return function(e) {
        var file = e.target.files[0];
        if (typeof file == 'undefined' || file == null) {
            return;
        }
        var imageType = /image.*/;
        if (!file.type.match(imageType)) {
            window.alert('Bad file type!');
            return;
        }
        var reader = new FileReader();
        reader.onloadend = function (e) {
            var imageLoader = new Image();
            imageLoader.onload = callback; //Put it here!
            imageLoader.src = e.target.result;
        };
        reader.readAsDataURL(file);
    };
}
然后这样称呼:

inputFile1.onchange = processFile(function() {
      //file processing for number 1
});
inputFile2.onchange = processFile(function() {
      //file processing for number 2
});
inputFile3.onchange = processFile(function() {
      //file processing for number 3
});

这里有一个EMCA5解决方案,只是为了把它加入到混合物中。它根据元素绑定动态事件回调

我假设每个字段都有一个ID(
input1
etc),但对代码进行一些修改(即通过其他方式识别触发器元素)后,就没有必要这样做了

Array.prototype.slice.call(document.querySelectorAll('input[type=file]')).forEach(function(element) {

    /* prepare code specific to the element */
    var input_specific_code = (function() {
        switch (element.id) {
            case 'input1': return function() { /* #input1 code here */ };
            case 'input2': return function() { /* #input2 code here */ };
            case 'input3': return function() { /* #input3 code here */ };
        }
    })();

    element.addEventListener('change', (function(input_specific_code) { return function(evt) {
        var id_of_trigger_input = element.id;

        /* common code here */

        /* element-specific code */
        input_specific_code();

        /* continuation of common code */

    }; })(input_specific_code), false);
});

不需要使用返回函数的函数。只需将onchange分配给公共函数。@jfriend00仍然需要一种方法将非公共函数与
输入[type=“file”]
相关联?您可以从
e
参数获取导致事件的对象,我看不到您对额外级别的函数做任何额外的操作。对我来说,这似乎不是必需的。我没有说过这是必需的,这只是一个可能的解决方案。我只是说除了增加复杂性之外,它没有任何意义。只需将内部函数设置为processFile,并删除外部级别,它就可以正常工作,只需减少一个级别的复杂性。为什么不直接将
element.id
放在开关中呢?此外,这种方法将创建n个函数,所有这些函数都包含所有n个输入的代码,但只需要其中一个。修改为使用闭包。
Array.prototype.slice.call(document.querySelectorAll('input[type=file]')).forEach(function(element) {

    /* prepare code specific to the element */
    var input_specific_code = (function() {
        switch (element.id) {
            case 'input1': return function() { /* #input1 code here */ };
            case 'input2': return function() { /* #input2 code here */ };
            case 'input3': return function() { /* #input3 code here */ };
        }
    })();

    element.addEventListener('change', (function(input_specific_code) { return function(evt) {
        var id_of_trigger_input = element.id;

        /* common code here */

        /* element-specific code */
        input_specific_code();

        /* continuation of common code */

    }; })(input_specific_code), false);
});