jQuery源码精髓-隐式new创建实例

最近在读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 :)。

你可能感兴趣的:(jQuery源码精髓-隐式new创建实例)