美文网首页我爱编程
jQuery源码精髓-隐式new创建实例

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

作者: BertieSama | 来源:发表于2016-12-16 13:35 被阅读0次

    最近在读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创建实例

        本文链接:https://www.haomeiwen.com/subject/txdnmttx.html