最近再看jQuery源码时,发现了一个这样有趣的事。

看下面一段代码:

 

 

var jquery = function () {

    // return new jquery.fn.init();
    // return new Object();
    // return 'a'
    // return {a:1}
};

jquery.fn = jquery.prototype = {
    constructor: jquery
};

jquery.fn.init = function () {
};

jquery.fn.init.prototype = jquery.fn;

var a = new jquery();
console.log(a);

 输出结果如下:

这和我们预期相符,a应该是jquery的一个实例,下面引用一段高程的原话。

要创建一个构造函数的新实例,必须使用new操作符。以这种方式调用构造函数实际上会经历以下4个步骤:

  1. 创建一个新对象
  2. 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
  3. 执行构造函数中的代码(为这个新对象添加属性)
  4. 返回新对象

所以使用new操作符调用构造函数(其实函数之前并没有区别,所谓构造函数也只是因为使用的是new操作符调用而已),如果构造函数没有显式返回值,则会返回一个构造函数的实例。那么问题来了,如果构造函数显示的提供了返回值呢?看下面的代码:

var jquery = function () {

    // return new jquery.fn.init();
    // return new Object();
    return 'a'
    // return {a:1}
};

jquery.fn = jquery.prototype = {
    constructor: jquery
};

jquery.fn.init = function () {
};

jquery.fn.init.prototype = jquery.fn;

var a = new jquery();
console.log(a);

这里我们显示的返回了一个字符串'a',但是发现a依然是jquery的一个实例

再换种情况:

var jquery = function () {

    // return new jquery.fn.init();
    // return new Object();
    // return 'a'
    return {a:1}
};

jquery.fn = jquery.prototype = {
    constructor: jquery
};

jquery.fn.init = function () {
};

jquery.fn.init.prototype = jquery.fn;

var a = new jquery();
console.log(a);

这次我们返回的是一个对象,然后通过new操作符调用之后发现,a不再是jquery的实例了,而是我们指定的对象。

经过反复试验和查阅资料,得出结论:

在javaScript中,如果在构造函数中显式的返回了复杂的对象时,此时使用new操作符调用构造函数将返回构造函数中指定的对象;当构造函数中显示返回的是类似于字符串和数字时,此时使用new操作符调用构造函数将返回构造函数的实例化对象。

这是javaScript语言的一个奇怪的特征,但有些时候这个特征确实有用。

比如说著名的jQuery中就用到了这个特性:

看下面这段代码:

"use strict";

var jquery = function () {
    return new jquery.fn.init();
};

jquery.fn = jquery.prototype = {
    constructor: jquery
};

jquery.fn.init = function () {
};

jquery.fn.init.prototype = jquery.fn;

var a = new jquery();
var b = jquery();
console.log(a);
console.log(b);

我们会发现,对于jquery这个函数,不管是用new操作符调用还是不用new操作符调用,其返回值都是一样的,这就得益于上面所提到了javaScript的这个古怪的特性了。

这样一来你就不用每次使用jQuery的时候,都需要new $('#id')了,因为new $('#id')和$('#id')返回值是一样的。

 

参考资料:

https://www.bennadel.com/blog/2522-providing-a-return-value-in-a-javascript-constructor.htm

http://www.w3dev.cn/article/20150912/javascript-constructor-return-value.aspx

https://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this