jQuery原型和构造函数链式调用

9

jQuery如何让其构造函数同时接受参数并充当函数的角色?

我对JavaScript还比较新,如果这是一个初级问题就抱歉了(我已经查看了源代码,但很难分析)。

无论如何,以$(document).ready(<args>);为例,构造函数$()和原型ready()都充当函数。为什么?因为如果我尝试这样做:

var $ = function( selector ) {
    if(selector == document) {
        return document;
    }
};

$.prototype = {
    constructor: $,
    ready: function( args ) {
        if( isDomReady ) {
            args.apply( document );
        } else {
            window.onload = args;
        }
    }
};

var isDomReady = ( document.addEventListener || document.readyState == ("complete"|"loaded"|true|4) || document.onreadystatechange() ) ? true : false;

$(document).ready(function() { alert("Wibbles!") });

我遇到了一个错误:Uncaught TypeError: Object[object global] has no method 'ready'

你没有通过在ready中返回this来链接方法。 - Jared Farrish
1
我知道你为什么会收到错误信息。$(document)只返回HTMLDocument,它没有.ready函数。如果$有一个"element"属性,在运行构造函数时存储文档元素,那么您可以通过在ready函数中访问存储的元素来检查其就绪状态。 - MattDiamant
@MattDiamant 啊...我想我会为了学习再读几遍那个评论。哈哈,但我想我明白了。谢谢。 - Jace Cotton
基本上,所有的方法都会返回调用它们的对象。 - Erik Reppen
2个回答

8
你知道的,这让我很感兴趣。虽然你已经接受了一个答案,但我还是想发布我的答案,以防它有用。这里创建了一个JSFiddle示例
jQuery = function( selector, context ) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init( selector, context );
};

jQuery.fn = jQuery.prototype = {
    constructor: jQuery,
    context: null,
    isReady: null,
    init: function( selector, context ) {
        if (selector === document){
            this.context = document;
            this.selector = document;
        }
        console.log(this);
        return this;
    },
    ready: function(func){
        var args = Array.prototype.slice.call(this, arguments),
            boundReadyFunc = func.bind(this, args.slice(1));

        if (this.isReady){
            func();
        }
        else {
            document.addEventListener( "DOMContentLoaded", this.onReady.bind(this, func), false );
        }
    },
    onReady: function(func){
        console.log("onready");
        this.isReady = true;
        func.call(this);
    },
};

jQuery.fn.init.prototype = jQuery.fn;
jQuery(document).ready(function(){
    alert("Hey, here I am");
});

让我尝试解释一下这是如何工作的。
每当你调用类似于$(selector)的东西时,都会创建一个新的jQuery实例,并提供你提供的选项(请参阅return new jQuery.fn.init(selector, context);)。
为了方便起见,我们将jQuery原型公开为另一个全局变量,即jQuery.fn。为了使其真正可链接,init函数必须返回一个新的jQuery实例。这就是为什么在最后,我们明确定义了jQueryjQuery.init两个原型是相同的。这样,你现在可以像链式调用函数一样进行函数调用。
$(document).ready(DoSomethingHere)

希望这有所帮助。

另外,你可以在 GitHub 上找到 jQuery 的源代码。它是模块化的并且相当容易理解。


谢谢!这更接近我想要的方向,但来得有点晚了,我已经开始使用函数链。不过还是谢谢! - Jace Cotton

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接