jQuery无new化探索

最近尝试着写dom库,发现了一个问题,就是jquery不用new就可以得到相应的对象实例,好奇之下发现网上已经有很多的分析和解释啦,但是看起来还是那么绕绕绕~~

没关系,来慢慢理解看看呗。先看最关键的几个源代码

jQuery = function( selector, context ) {
  return new jQuery.fn.init( selector, context );
}
jQuery.fn = jQuery.prototype = {
  jquery: version,
  constructor: jQuery,
...
}
init = jQuery.fn.init = function( selector, context, root ){}
init.prototype = jQuery.fn;

window.jQuery = window.$ = jQuery;

具体实现就不贴了,很复杂怕怕。。。就单说无new化,其实就是$()就是调用了jQuery这个构造函数,而这个函数里面是返回的一个new的init构造方法,所以实际上$()拿到的jquery对象的构造函数是init。这里很容易有两个问题让人迷惑。

  1. 为什么是init是构造函数,直觉上直接jQuery当构造函数不是更清晰么?
jQuery = function( selector, context ) {
  return new jQuery( selector, context );
}

矣。。很多分析的文章也都会提到,死循环了。。。所以可以想出,方法想要返回一个new好的实例,new该方法本身肯定是不行的,因为一个方法既想返回一个对象,又想把自己的实例返回去,这两个职责是矛盾的,所以怎么办呢,借助另一个构造函数呗?ok,那么问题2来了,也很困扰我。。。

  1. 为啥非要用jQuery.fn.init这个作为构造函数呢?

是啊,我直接用一个新的函数作为构造函数不行么,比如:

var init = function( selector, context ) {}

又或者挂到jQuery上?比如:

jQuery.init = function( selector, context ) {}

为什么偏偏挂到了jQuery.fn.init上呢?????真是让人头大啊,为啥呢????绕来绕去是为啥呢?而且注意到这句

init = jQuery.fn.init = function( selector, context, root ){}
init.prototype = jQuery.fn;

为了让jQuery.fn.init构造函数new出的对象能够使用jQuery原型上的方法还要重新赋值一下,那其实这些用另外两种方式都可以啊,为啥还是挂在了jQuery.fn.init上呢?

在网上搜索了不少答案都不是很清晰,欢迎大神们指教。有一种说法感觉有些道理,就是说如果在jquery代码外部,用户希望用jquery实例调用init方法来实例化一个jquery对象(什么场景会用到呢?实例化直接$()不就得了,用什么init啊,有一种场景就是比如你想继承jquery类,这个时候在子构造方法里使用init()来使用父的构造方法,也就是这种写法有利于继承,而以上两种我说的写法的第一种var init没有暴露不能这么调用,而第二种jQuery.init挂在了类上,实例并不能调用。)以下是stack上一段代码的解释。

function MyJQuery(selector, context) {
    this.init(selector, context, MyJQuery.root); // <==
    // or more explicit:
    // jQuery.fn.init.call(this, selector, …);
    …
}
MyJQuery.fn = MyJQuery.prototype = Object.create(jQuery.fn);
MyJQuery.root = jQuery(document);

嗯嗯,,绕把绕吧,绕绕更健康哈哈哈哈~