阿西河

所有教程

公众号
🌙
阿西河前端的公众号

我的收藏

    最近访问  (文章)

      教程列表

      抓包专区
      测试专区

      jQuery 的源码看过吗?能不能简单概况一下它的实现原理?

      jQuery 的源码看过吗?能不能简单概况一下它的实现原理?

      1、闭包机制;

       // 以下截取自 jquery 源码片段
       (function( window, undefined ) {
          /*    源码内容    */
       })( window );
      

      上面这一小段代码来自于 1.9.0 当中 jquery 的源码,它是一个无污染的 JS 插件的标准写法,专业名词叫闭包。可以把它简单的看做是一个函数,与普通函数不同的是,这个函数没有名字,而且会立即执行

      我们将里面的变量变成了局域变量,这不仅可以提高运行速度,更重要的是我们在引用 jquery 的 JS 文件时,不会因为 jquery 当中的变量太多,而与其它的 JS 框架的变量命名产生冲突;闭包中的变量声明没有污染到外面的全局变量;;

      2、作为全局的一个属性;

      window.jQuery = window.$ = jQuery;
      

      这一句话将我们在闭包当中定义的 jQuery 对象导出为全局变量 jQuery 和 $,因此我们才可以在外部直接使用 jQuery 和 $。

      window 是默认的 JS 上下文环境,因此将对象绑定到 window 上面,就相当于变成了传统意义上的全局变量,

      3、最核心的功能,就是选择器;

      首先我们进入 jquery 源码中,可以很容易的找到 jquery 对象的声明,看过以后会发现,原来我们的 jquery 对象就是 init 对象。

      jQuery = function( selector, context ) {
      	return new jQuery.fn.init( selector, context, rootjQuery );
      }
      

      这里出现了 jQuery.fn 这样一个东西,它的由来可以在 jquery 的源码中找到,它其实代表的就是 jQuery 对象的原型。

      jQuery.fn = jQuery.prototype;
      jQuery.fn.init.prototype = jQuery.fn;
      

      这两句话,第一句把 jQuery 对象的原型赋给了 fn 属性,第二句把 jQuery 对象的原型又赋给了 init 对象的原型。也就是说,init 对象和 jQuery 具有相同的原型,因此我们在上面返回的 init 对象,就与 jQuery 对象有一样的属性和方法。

      我们不打算深究 init 这个方法的逻辑以及实现,但是我们需要知道的是,jQuery 其实就是将 DOM 对象加了一层包裹,而寻找某个或者若干个 DOM 对象是由 sizzle 选择器负责的,

      jQuery 对象有很多的属性和方法;对于属性来说,我们最需要关注的只有一个属性,就是 [0] 属性,[0] 其实就是原生的 DOM 对象。

      很多时候,我们在 jQuery 和 DOM 对象之间切换时需要用到 [0] 这个属性。

      从截图也可以看出,jQuery 对象其实主要就是把原生的 DOM 对象存在了 [0] 的位置,并给它加了一系列简便的方法。

      这个索引 0 的属性我们可以从一小段代码简单的看一下它的由来,下面是 init 方法中的一小段对 DOMElement 对象作为选择器的源码。

      // Handle $(DOMElement)
      if ( selector.nodeType ) {
      	/*     可以看到,这里将 DOM 对象赋给了 jQuery 对象的 [0] 这个位置  */
      	this.context = this[0] = selector;
      	this.length = 1;
      	return this;
      }
      

      这一小段代码可以在 jquery 源码中找到,它是处理传入的选择参数是一个 DOM 对象的情况。

      可以看到,里面很明显的将 jQuery 对象索引 0 的位置以及 context 属性,都赋予了 DOM 对象

      。代码不仅说明了这一点,也同时说明了,我们使用 $(DOMElement) 可以将一个 DOM 对象转换为 jQuery 对象,从而通过转换获得 jQuery 对象的简便方法。

      4、ready 方法

      $(function(){}) 或者是 ready 方法;

      实现类似 jquery 的 ready 方法的效果我们是可以简单做到的,它的实现原理就是,维护一个函数数组,然后不停的判断 DOM 是否加载完毕,倘若加载完毕就触发所有数组中的函数。

      遵循着这一思想,LZ 拿出很久之前写的一个小例子,来给各位看一下。

      (function( window, undefined ) {
      var jQuery = {
              isReady:false,// 文档加载是否完成的标识
              readyList:[],// 函数序列
              //onload 事件实现
              ready : function(fn){
                      // 如果是函数,加入到函数序列
                      if(fn && typeof fn == 'function' ){
                          jQuery.readyList.push(fn);
                      }
                      // 文档加载完成,执行函数序列。
                      if(jQuery.isReady){
                          for(var i = 0;i < jQuery.readyList.length ;i++){
                              fn = jQuery.readyList[i];
                              jQuery.callback(fn);
                          }
                          return jQuery;
                      }
                  },
              // 回调
              callback : function(fn){
                  fn.call(document,jQuery);
              }
          };
          // 导出对象
          window.$ = window.jQuery = jQuery;
          // 判断加载是否完成
          var top = false;
          try {
              top = window.frameElement == null && document.documentElement;
          } catch(e) {}
          if ( top && top.doScroll ) {
              (function doScrollCheck() {
                  try {
                      top.doScroll("left");
                      jQuery.isReady = true;
                      jQuery.ready();
                  } catch(e) {
                      setTimeout( doScrollCheck, 50 );
                  }
              })();
          }
      }(window));
      

      这段代码是 LZ 从之前的例子摘出来的,它的实现逻辑非常简单,但是可以达到 jQuery 的 ready 方法的效果,

      5、extend 方法

      简单说两个 extend 方法的常用方式。

      • 1、使用 jQuery.fn.extend 可以扩展 jQuery 对象,使用 jQuery.extend 可以扩展 jQuery,前者类似于给类添加普通方法,后者类似于给类添加静态方法。
      • 2、两个 extend 方法如果有两个 object 类型的参数,则会将后面的参数对象属性扩展到第一个参数对象上面,扩展时可以再添加一个 boolean 参数控制是否深度拷贝。

      更多面试题

      如果你想了解更多的前端面试题,请点击下面进行选择,这里基本包涵了市场上的所有前端方面的面试题,让你面试更加顺利。

      这些题库还在更新中,如果你有不错的面试题库欢迎分享给我,我整理后放上来;人人为我,我为人人,互帮互助,共同提高,祝大家都拿到心仪的Offer!

      目录
      目录