最近再看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个步骤:
- 创建一个新对象
- 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回新对象
所以使用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