老年人的码农梦

导航

jQuery 最外面的那层皮

这次学习 jQuery 源码,基于当前最新的版本,3.2.1。

IIFE

(function() {
    'use strict';
    //
})();

定义一个匿名函数并立即执行,得益于 javascript 奇葩的特性,只能据此模拟命名空间。

利用 IIFE 来建立命名空间需要 3 步( 《Web开发权威指南》 ):

  1. 如果命名空间已经存在,获取它的引用。

  2. 创建模块代码。

  3. 将模块代码绑定到命名空间上。

按照这个思路扩展下代码:

(function(window) {
    'use strict';

    var jQuery = window.jQuery || {};

    // jQuery.xxx = xxx;

    window.jQuery = jQuery;
})(window);

自己的组件如此操作是可行的, jQuery 这样的库跟别的库、框架共用一个命名空间就很不合适了:

(function(window) {
    'use strict';

    var jQuery = function() {};

    // 保存原有的命名,防止覆盖、冲突
    var _jQuery = window.jQuery, _$ = window.$;

    // 把命名还回去
    jQuery.noConflict = function(deep) {
        if(window.$ === jQuery) {
            window.$ = _$;
        }

        if(deep && window.jQuery === jQuery) {
            window.jQuery = _jQuery;
        }

        return jQuery;
    }

    window.jQuery = window.$ = jQuery;

    return jQuery;
})(window);

CommonJS 支持

要判断是否处于 CommonJS 规范相关的环境,只要判断 moduleexports 这些变量是否存在即可:

(function(global, factory) {
	"use strict";

	if (typeof module === "object" && typeof module.exports === "object") {
		module.exports = factory(global);
	} else {
		factory(global);
	}

})(typeof window !== "undefined" ? window : this, function(window) {
	'use strict';

	var jQuery = function() {};

	window.jQuery = window.$ = jQuery;

	return jQuery;
});

Node 采用的 CommonJS 模块规范,用 Node 写例子:

var jQuery = require('./jQuery');

console.log(jQuery);

运行可见,能如愿正确导出。

AMD 支持

(function(global, factory) {
	"use strict";

	if (typeof module === "object" && typeof module.exports === "object") {
		module.exports = factory(global);
	} else {
		factory(global);
	}

})(typeof window !== "undefined" ? window : this, function(window) {
	'use strict';

    var jQuery = function() {};
    
    if ( typeof define === "function" && define.amd ) {
        define( "jquery", [], function() {
            return jQuery;
        } );
    }

	window.jQuery = window.$ = jQuery;

	return jQuery;
});

document

jQuery 归根结底是一个快捷操作 DOM 的库,换句话说,脱离了浏览器,就没啥用了。

浏览器环境,jQuery 是通过 document 属性来判断的。

这里面又分两种情况:

  1. 调用者本身就有 document 属性,则直接执行 factory,返回 jQuery
  2. 调用者本身没有 document 属性,返回一个带一个参数的函数,根据这个参数是否有 document 再处理。

另外,通过 CommonJS 模块化导出,并不需要把 jQuery 直接绑在调用者身上,直接返回就好了,修修补补后,最外层的骨骼就长这样:

(function(global, factory) {
	"use strict";

	if (typeof module === "object" && typeof module.exports === "object") {
		module.exports = global.document ?
			factory(global, true) :
			function(w) {
				if (!w.document) {
					throw new Error("jQuery requires a window with a document");
				}
				return factory(w);
			};
	} else {
		factory(global);
	}

})(typeof window !== "undefined" ? window : this, function(window, noGlobal) {
	'use strict';

	var jQuery = function() {};

	if ( typeof define === "function" && define.amd ) {
		define( "jquery", [], function() {
			return jQuery;
		} );
	}

    var _jQuery = window.jQuery, _$ = window.$;

    jQuery.noConflict = function(deep) {
        if(window.$ === jQuery) {
            window.$ = _$;
        }

        if(deep && window.jQuery === jQuery) {
            window.jQuery = _jQuery;
		}

		return jQuery;
	}

	if ( !noGlobal ) {
		window.jQuery = window.$ = jQuery;
	}

	return jQuery;
});

后续

模块化的东西并不是 jQuery 的核心部分,也就追求个有就成,所以这系列的后续代码都是基于简化后的骨架来的:

(function(window) {
    var jQuery = function() {};

    window.jQuery = window.$ = jQuery;
})(window);

代码地址:

https://github.com/oldmanscode/jq_step_by_step/blob/master/step1.js

posted on 2017-12-15 09:02  老年人的码农梦  阅读(803)  评论(0)    收藏  举报