最近在读underscore源码的时候,又遇见了需要隐式new构建的模式,虽然之前有过了解,但是并未记得,所以在网上找攻略,然后现在将自己的心得写出来,也一方面或许能对他人有所帮助。(一般来讲是无new,但是我认为这会误导理解,所以我在本文中所用是隐式new,原因我会在下面说,且本文主要针对的是对类库的架构有兴趣且已经对JavaScript有一定了解的读者。)
一般来说,我们会在script标签内中这样使用jQuery。
$('#demo').html('hello');//创建一个jQuery实例,然后返回这个实例并进行操作。
或者你也可以这样
var demo =new $('#demo');
demo.html('hello');
我认为在日常的使用中,大部分人都会选择用第一种方法,因为简单且便捷,其实$('')和new $('')所发生的事情是一样的,那么我们来看看在jQuery内部是如何架构的。
(function (window, undefined) {
var jQuery = function(selector, context) {
// 返回一个jQuery原型下的init方法的实例
return new jQuery.fn.init(selector, context, rootjQuery);
},
jQuery.fn = jQuery.prototype = {
init: function(selector, context, rootjQuery) {
// ...
}
}
jQuery.fn.init.prototype = jQuery.fn;
window.$===undefined&&(window.$=jQuery);
})(window);
那么我们先不要急着理解上面的代码,现在我们来一步步理解为什么要这样写。
1.我们要做的第一件事是我们需要有一个东西用来返回实例。那么我们可能会这样做:
var jQuery = function(selector, context) {
return new jQuery();
}
jQuery.prototype = {
name:'Bertie',
age:function(age){
return age;
}
}
虽然可以了,但是这样就会造成死循环,那么我们就需要转变思路,其实我们可以把jQuery类当作一个工厂方法来创建实例,把这个方法放到jQuery原型中:
var jQuery = function(selector, context) {
return jQuery.prototype.init(selector);
}
jQuery.prototype = {
// ...
}
但是如今又有一个缺陷,那么就是只生成了一个实例,并且在实际使用中,肯定不止一个要实例一个对象了,有#demo,就会有#demo2.#demo3...,那么咱们需要对以上的代码做一点修改:
var jQuery = function(selector, context) {
return new jQuery.prototype.init(selector);
}
jQuery.prototype = {
init:function (param) {
if (param instance String) {
this.name=param;
}
return this;//将jQuery实例用原型下的init代替实例化
},
name:'',
age:''
}
这样就可以隔离不同的this作用域,需要用到new 而不是直接返回jQuery.prototype.init(seletor);,每调用(每实例一次)就会创建一个新的this作用域。
那么我们就剩下最后一件事情要做了就是,init上没有我们想要的属性和方法,就是我们想把属性和方法放到jQuery的原型下,而不是init原型下,因为在每次调用的时候,可以不用多在原型链上在多找一层(如果将属性和方法放在init上的话),并且对性能也有提升,那我们就这样干吧:jQuery.prototype.init.prototype = jQuery.prototype:
(function (window, undefined) {
var jQuery = function(selector, context) {
return new jQuery.fn.init(selector, context, rootjQuery);
},
jQuery.fn = jQuery.prototype = {
init: function(selector, context, rootjQuery) {
// ...
}
}
jQuery.fn.init.prototype = jQuery.fn;
window.$===undefined&&(window.$=jQuery);
})(window);
现在再回到jQuery的源码来看的话是不是就可以若然开朗了呢?
到现在或许你也明白了为什么我说无new会误导理解了吧,的确需要用new实例化了,但是不是jQuery本体,而是jQuery原型上的某个方法。
题后话
一直都想写自己的技术博客,但是一直都在拖延,因为现在在读underscore的源码,然后想把整个学习过程记录下来,之后我会一步步更新我学习underscore的源码精髓,当然,还有我所擅长的重构和性能优化领域,和有趣的前端知识,也都会分享到我的中,so,c u next time :)。