随笔:用心良苦 - 理解 jQuery 的构造函数

最近有人问 jQuery 的构造函数为什么写的那么奇怪,不好理解。

其实我刚开始看 jQuery 源码的时候也有这个疑问,下面是 jQuery 构造函数的关键代码:

jQuery = function( selector, context ) {
    return new jQuery.fn.init( selector, context );
},

jQuery.fn = jQuery.prototype = {
    constructor: jQuery,
}

init = jQuery.fn.init = function( selector, context ) {
     return jQuery.makeArray( selector, this );
}

虽然只有短短几行,但是不理解构造函数和原型链的童鞋很容易产生这么几个疑问:

  • 为什么要 return new jQuery.fn.init( selector, context ); 而不是 return this 或者省略
  • fnprototype 是什么关系,为什么要叫 fn
  • constructor: jQuery 是干嘛的
  • init 函数里面返回的是什么

首先说说第一个问题,这个问题是关键。我们一般的构造函数都是这样的:

People = function() {
    return this;//这一行可有可无
}

其中 return this 有没有都无所谓。因为在JS中,通过 new 关键字创建的对象,遵守如下规则:

  • 如果构造函数返回了一个对象,那么构造出的对象就是返回的这个对象。
  • 如果构造函数没有返回值,那么相当于 return this

而我们再看 jQuery 的构造函数:

jQuery = function( selector, context ) {
    return new jQuery.fn.init( selector, context );
},

这里返回了一个对象,因此,我们用不用 new 关键字都是一样的,最终得到的都是一个 new jQuery.fn.init( selector, context ); 实例。

对!这就是它的这一奇怪的构造函数写法的目的,就是为了能让我们在创建 jQuery 对象的时候省略 new 关键字:

a = $(“a”);

但是这样做有一个副作用,就是 a 其实不是 jQuery 的实例,而是 jQuery.fn.init 的实例。所以需要修正一下 constructor:

jQuery.fn = jQuery.prototype = {
    constructor: jQuery,
}

这样我们用 a instanceof jQuery 的时候就不会返回 false 了:

a instanceof jQuery; //true
a instanceof jQuery.fn.init; //true

那么那个奇怪的 fn 是干嘛的?其实 fn 就是一个 prototype 的别名而已,因为 prototype 名字太长了写起来麻烦,并且由于是特殊属性在压缩代码的时候无法被压缩, 他们完全是等价的。

这样前三个问题我们都有答案了,至于最后一个问题 return jQuery.makeArray( selector, this ); 返回的是啥玩意?看看 makeArray 的代码就知道了,其实返回的就是 this

所以总结一下,jQuery 的构造函数为什么写的这么奇怪?归根结底原因很简单,就是为了能在创建 jQuery 对象的时候省略一个 new 关键字。为了让大家用的爽,真是用心良苦啊。

你可能感兴趣的:(jquery,构造函数)