jQuery部分源码剖析

JS代码执行的环境

  • 浏览器:PC端、移动端 「webkit、gecko、trident、blink…」(window)

  • Hybrid混合APP开发:把H5页面嵌入都native app(IOS/安卓)的webview中「webkit」(window)

  • node:一个基于v8引擎,渲染和解析JS的环境(没有window,全局对象global)

  • 小程序

jQuery部分源码剖析

//(function(){}()) 等价 (function(){})()
//jQuery源码中自执行函数 (function(){}())

//首先分析一下这个自执行函数的形参和实参
(function(global, factory){
    //区分环境
}(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
    //具体代码
}))
/*
第一个实参:typeof window !== "undefined" ? window : this 结果记为A
  如果A===window:说明是浏览器、webview中运行
  如果是在Node环境下运行,A可能是Global,也可能是当前模块
第一个实参是为了区分js代码执行环境,使用typeof判断的好处是,即使当前环境没有window也不会报错,因为typeof 一个不存在的变量,其结果是undefined
*/

/*------------------------------------*/
	(function (global, factory) {
    	/*区分环境,不同环境下执行回调函数factory(window, noGlobal)
        浏览器环境下执行这个函数
           window -> window
           noGlobal -> undefined
        webpack环境下导入执行
           window -> window
           noGlobal -> true
        */
    
    // module 和 module.exports 属于 CommonJS模块规范 例如:Node、webpack
      if (typeof module === "object" && typeof module.exports === "object") {
          
            //只有window才有document
            // 既支持CommonJS规范,也有window  例如:webpack工程化环境
            /* =>module.exports=jQuery;
            外部使用方式:
               import $ from 'jquery'   $->jQuery
               let $=require('jquery')  $->jQuery
            */
        module.exports = global.document ?
          factory(global, true) :
          function (w) {
            if (!w.document) {
                //如果没有window就抛出异常,说明jQuery必须在有window的环境下运行
              throw new Error("jQuery requires a window with a document");
            }
            return factory(w);
          };
      } else {
          // 不支持CommonJS规范的 例如:浏览器环境
        // global->window
        //外部使用方式 <script src='jquery.min.js'></script>
        factory(global);// window
      }
    }(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
    //获取数组原生方法
      var deletedIds = [];
      var slice = deletedIds.slice;
      var concat = deletedIds.concat;
      var push = deletedIds.push;
      var indexOf = deletedIds.indexOf;
    //获取对象原生方法
      var class2type = {};
      var toString = class2type.toString;
      var hasOwn = class2type.hasOwnProperty;
      var support = {};
    
      var version = "1.11.3";
      
    /*
    我们在外面拿到的不是一个真正的jQuery实例,而是一个jQuery.fn.init实例
     var jQuery = function (selector, context) {
         return new jQuery(selector, context);//不能直接返回自己的实例,会形成"死递归"
      };
      jQuery();
    */
      var jQuery = function (selector, context) {
        return new jQuery.fn.init(selector, context);
      };

    // 给jQuery的原型进行重定向(jQuery是自己定义的一个函数,重定向没有什么损失)
      jQuery.fn = jQuery.prototype = { 
        jquery: version,
        constructor: jQuery,// 重定向的原型没有constructor,所以手动增加了一个constructor
          
        //类数组转数组,原生写法:[].slice.call(this)
        toArray: function () {
          return slice.call(this);
        },
        
        //取得其中一个匹配的元素。 num表示取得第几个匹配的元素。从0开始,返回的是原生DOM对象。
        get: function (num) {
          return num != null ?

            // Return just the one element from the set
            (num < 0 ? this[num + this.length] : this[num]) :

            // Return all the elements in a clean array
            slice.call(this);
        },
        //...
      }
    
    /*扩展jQuery的功能
    // 往jQuery自己身上拓展方法
    jQuery.extend({ 
       sss: function () {
         console.log('我是拓展的方法');
       }
    });
	// 往jQuery的原型上拓展方法
    jQuery.fn.extend({ 
      fff: function () {
         console.log('我是拓展的方法');
       }
    })
    */
    jQuery.extend = jQuery.fn.extend = function() {
        //...
    }

    /*
    前面已经将jQuery原型进行重定向,并且jQuery.fn = jQuery.prototype
    */
      var init = jQuery.fn.init = function (selector, context) {
        // 当$执行时new的是当前这个函数
        // init函数里的代码就是获取dom的
      }
      init.prototype = jQuery.fn; // 把jQuery的原型赋值给init的原型

      /* 冲突处理:转让$和jQuery的使用权 */
    //暂存用户当前的jQuery、$变量
      var _jQuery = window.jQuery; 
      var _$ = window.$;
      jQuery.noConflict = function (deep) {
        if (window.$ === jQuery) {
          window.$ = _$;//转让$的使用权
        }

        if (deep && window.jQuery === jQuery) {
          window.jQuery = _jQuery;//转让jQuery的使用权
        }

        return jQuery;//返回jQuery供用户接收(用户可自定义使用jQuery功能的变量名)
      };
    
      /* 暴露API */
        if (typeof define === "function" && define.amd) {
            define("jquery", [], function () {
                return jQuery;
            });
        }
      if (typeof noGlobal === "undefined") {
		// 给window增加键值对
        window.jQuery = window.$ = jQuery;
      }
    return jQuery;
    }))
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值