为什么写 $("document").ready() 仍然成功?

背景

在学习 jQuery 的时候,误把 $(document).ready() 写成了 $("document").ready() 后,ready 内的代码仍然成功执行?

问题

想问下为什么会这样?

阅读 3.2k
2 个回答

按照这份源码给你回答一下:
https://github.com/jquery/jquery/blob/1.4.2/src/core.js

$("document")结果是什么

$("document")应该通过jQuery.fn.init( selector, context );这个函数来构造jQuery对象,
这个函数有很多的分支,$("document")落在114行代码的这个分支上。

if ( !context || context.jquery ) {
    return (context || rootjQuery).find( selector );
}

这里的contextundefined,根据短路原则if判断为真,所以执行
return (context || rootjQuery).find( selector );
但是这里又有分支,不难看出最终执行的是

return (rootjQuery).find( selector );

rootjQuery是在722行赋值的rootjQuery = jQuery(document);
因此,$("document")最终是jQuery(document).find("document");
这个是结果是个jQuery对象:

clipboard.png

jQuery.ready()函数

从231到247行是ready函数的定义

ready: function( fn ) {
        // Attach the listeners
        jQuery.bindReady();

        // If the DOM is already ready
        if ( jQuery.isReady ) {
            // Execute the function immediately
            fn.call( document, jQuery );

        // Otherwise, remember the function for later
        } else if ( readyList ) {
            // Add the function to the wait list
            readyList.push( fn );
        }

        return this;
    },

可以看出ready函数接受一个回调函数fn作为参数,当jQuery.isReady条件成立时就执行回调函数,否则将回调函数放入队列中(wait list)。这里并不要求特殊的jQuery对象才能执行ready方法,主要判断逻辑还是jQuery.isReady

jQuery.isReady

这个有空再来补充。

总结

仔细读源码,init函数的这么多分支中只提到了$("body")可以做下“特殊处理”外,并没有提到"document"的情况;
我觉得jQuery("segmentfault").ready(function(){console.log("happy");});这段代码也能跑通并输出"happy";

clipboard.png

不能忽略的前提就是jQuery要有定义。

document 是 element 类参数,不进入选择器解析过程,直接包装返回。类似的如 window。但是给它加上引号,就成了一个标签名,显然找不到。不过 $()始终返回一个 jQuery对象,所以可以执行 ready()。body加引号,是标签名,当然找得到。也可以传入 document.body,这样速度会快点,因为不走选择器解析过程。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进