为什么'jQuery'必须传递给这个函数(参见最后一行代码)?

时间:2013-10-08 20:30:03

标签: javascript jquery

来源: http://blog.tomasjansson.com/creating-custom-unobtrusive-file-extension-validation-in-asp-net-mvc-3-and-jquery

$(function () {
    jQuery.validator.unobtrusive.adapters.add('fileextensions', ['fileextensions'], function (options) {
        var params = {
            fileextensions: options.params.fileextensions.split(',')
        };

        options.rules['fileextensions'] = params;
        if (options.message) {
            options.messages['fileextensions'] = options.message;
        }
    });

    jQuery.validator.addMethod("fileextensions", function (value, element, param) {
        var extension = getFileExtension(value);
        var validExtension = $.inArray(extension, param.fileextensions) !== -1;
        return validExtension;
    });

    function getFileExtension(fileName) {
        var extension = (/[.]/.exec(fileName)) ? /[^.]+$/.exec(fileName) : undefined;
        if (extension != undefined) {
            return extension[0];
        }
        return extension;
    };
} (jQuery));

在这个函数中jQuery是否已经可用,为什么它会在那里传入?我没有得到这个,我之前已经看过几次了,从来没有使用过它,很好奇这里发生了什么。

3 个答案:

答案 0 :(得分:2)

传递它没有做任何事情。该语法不正确,因为在那里使用的函数是回调而不是IIFE。

如果没有使用冲突模式,我认为这样做的唯一理由就是这样。即使这样,语法仍然不正确。

答案 1 :(得分:1)

阅读更多:jQuery.noConflict

我们将jQuery或其他jQuery Control变量($,jQuery,jq,jQ,jQ1101)传递给模块或插件,因为在DOM中,我们可以加载多个版本的jQuery,或者我们可以使用其他库来使用$ as控制变量。例如PrototypeJSZepto

通过传递jQuery Control变量,我们确保我们的模块有正确的控制变量,在内部我们只使用$作为jQuery变量。

请看这个例子。

<html>
    <head>
        <title>StackOverflow 19257741</title>
        <script type="text/javascript" src="http://zeptojs.com/zepto.min.js"></script>
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    </head>
    <body>
        <div id="content">
            <!-- Other HTML Tags -->
        </div>
    </body>
    <script type="text/javascript">
        //Change jQuery Control because you have other library loadded or you have multiple jQuery loaded.
        var jQ1101 = jQuery.noConflict(true);

        //Now, you can not access jQuery by $ or jQuery


        //This module have to have jQuery to do DOM Manipulation
        var module = (function ($, zepto) {

            var i = 0,  //private ivar for module use only.
                _init = function () {
                    var me = this;

                    //TODO: Module can init or do something here...

                    return me;
                },
                _fill = function (selector) {
                    //We can use $ here as jQuery Control
                    $(selector).css({ "backgroundColor": "#000000", "width": "100%", height: "100%" });

                    //Wait for 2 seconds
                    window.setTimeout(function() {
                        //Not select dom with zepto
                        zepto(selector).css({ "backgroundColor": "#777777", "width": "100%", height: "100%" }); 
                    }, 2000);
                };

            return {
                init: _init,
                fill: _fill
            };

        })(jQ1101, $);  //We have to pass the current Control for jQuery so, module can use library for internal function.

        //Call module then call fill method by passing variable
        module.init().fill("#content");

        //Two different Library
        console.log(jQ1101.fn.jquery);  //jQuery 1.10.1
        console.log($); //Zepto
    </script>
<html>

答案 2 :(得分:0)

该博客文章中的代码是有效的JavaScript语法并将执行,但它不会执行作者可能期望的内容。 $(function...)调用看起来像尝试以通常的方式在DOM上运行该函数,但事实并非如此。

让我们解构代码。首先,删除函数中的所有代码并添加一些日志记录:

console.log( 'before' );

$( function () {
    console.log( 'DOM ready' );
} (jQuery) );

console.log( 'after' );

这是(可能令人惊讶的)有效的JavaScript并将记录:

before
DOM ready
after

但问题在于:如果您将该脚本放在网页中,您真的希望它能够记录:

before
after
DOM ready

毕竟,您在DOM准备好之前运行脚本,期望在DOM准备就绪后稍后运行该函数。这就是使用$()电话的重点。

出了什么问题?为了更清楚,让我们将内部函数分解为单独的命名函数:

console.log( 'before' );

function ready() {
    console.log( 'DOM ready' );
}

$( ready(jQuery) );

console.log( 'after' );

还有一个改变是完全一步一步地完成:

console.log( 'before' );

function ready() {
    console.log( 'DOM ready' );
}

var result = ready( jQuery );

$( result );

console.log( 'after' );

这些版本中的每一个都具有完全相同的语义,并以相同的顺序运行。

现在应该清楚发生了什么。我们立即调用ready函数 并将其返回值传递给$()调用。 ready函数不返回任何值,因此该值为undefined

最后一行相当于:

$( undefined );

该调用只返回一个空的jQuery对象([])。

当然,罪魁祸首是(jQuery)。添加它是导致函数立即被调用的原因,而不是将引用传递给函数进入$()调用。并且括号内jQuery的存在是没有意义的:这个ready函数不期望任何参数,因此被忽略。如果()出现在那里会是同样的事情。

这非常像您在setTimeout()和类似电话中看到的常见错误:

// Oops - calls doStuff immediately, not after one second
setTimeout( doStuff(), 1000 );

这提出了一个问题:为什么这个代码没有遇到问题,因为它没有按预期工作?好吧,该函数确实被调用 - 唯一的区别是当它运行时。

因此有两个可能的原因导致它没有出现问题。

  1. 这段代码可能已经放置在<body>的末尾,这是目前流行的做法。在这种情况下,当代码运行时,DOM可能就足够了。在加载<body>时按顺序创建DOM元素,如果在特定DOM元素之后放置<script>标记,则在运行该脚本时该DOM元素确实可用。

  2. 代码可能不需要DOM准备就绪。查看博客文章中的验证器代码,它看起来像设置代码,它在首次运行时对DOM没有任何作用。如果是这样,那么只要jQuery.validator插件已经加载,那么如果这个代码立即运行或者在完整DOM准备就绪后运行它就没有任何区别。