jQuery 无 new 构建实例
无 new 化构建
在 jQuery 中 $ 符号就是 jQuery 的别称
$() 就是创建了 jQuery 的实例对象
实现
- (function(root){
- function jQuery() {
- return new jQuery.prototype.init();
- };
- // 在 jQuery 的原型上定义 init 方法
- jQuery.prototype = {
- init: function() {
- },
- CSS: function() {
- // 在 jQuery 原型上扩展的属性也会被共享到 init 的原型上
- }
- }
- // 把 jQuery 的原型共享给 init 的原型
- jQuery.prototype.init.prototype = jQuery.prototype;
- // 设置全局变量 $ 和 jQuery
- root.$ = root.jQuery = jQuery;
- })(this); // 把宿主对象 Windows 传进
共享原型设计
描述
如上, 在实现 jQuery 实例化的时候, 我们直接调用 $();
console.log($());
因为 $() 指向的是 jQuery 函数, 所以相当于调用了 jQuery 函数;
- // 设置全局变量 $ 和 jQuery;
- // $ 和 Windows.jQuery 指向的都是 jQuery 函数
- root.$ = root.jQuery = jQuery;
jQuery 作为构造函数直接被调用效果和普通函数呗调用一样,
所以无法生成有效实例;
解决方案:
只能把 jQuery 函数的返回值设成构造函数的实例;
- function jQuery() {
- return new jQuery();
- };
但是这样做是不行的, 很明显会造成死循环
所以 jQuery 采用的共享原型的设计模式, 即;
在 jQuery 函数的 prototype 上定义了 init 方法
- // 在 jQuery 的原型上定义 init 方法
- jQuery.prototype = {
- init: function() {
- }
- }
把 jQuery 的原型共享给 init
- // 把 jQuery 的原型共享给 init 的原型
- jQuery.prototype.init.prototype = jQuery.prototype;
通过 $() 调用 jQuery 函数时返回一个 init 的实例
- function jQuery() {
- return new jQuery.prototype.init();
- };
给 jQuery 的 prototype 扩展属性的时候, 由于原型共享,
所以 init 的原型上也会具有该扩展属性
- jQuery.prototype = {
- init: function() {
- },
- CSS: function() {
- // 在 jQuery 原型上扩展的属性也会被共享到 init 的原型上
- }
- }
- console.log($());
123.PNG
以上就是 jQuery 无 new 实例化的实现
原型扩展设计见下图:
1122.PNG
extend 函数源码解析
extend 函数用法:
- // 给任意对象扩展
- var obj1 = { a:1, b:2 };
- var obj2 = { c: 3 };
- var res = $.extend(obj1, obj2);
- console.log(res); // ===> { a:1, b:2, c: 3 }
- console.log(obj1); // ===> { a:1, b:2, c: 3 }
- // 给 $(jQuery) 进行扩展
- $.extend({
- myMethod: function() {
- console.log('myMethod1');
- }
- })
- $.myMethod(); // myMethod1;
- // 给 $(jQuery) 的实例进行扩展
- $.fn.extend({
- myMethod: function() {
- console.log('myMethod2');
- }
- })
- $().myMethod(); // myMethod2;
extend 函数用于给对象进行扩展, 给 jQuery 提供了插件机制
可以给任意对象扩展
也可以给 jQuery 自身扩展
注:
- // $.fn 指向的就是 $.prototype
- jQuery.fn = jQuery.prototype = {
- // ......
- }
extend 再 jQuery 中之所以既能通过 $.extend 调用,
又能通过 $().extend 调用是因为在源码内部中实现了
jQuery.fn.extend = jQuery.extend = function() { // ...... }
extend 实现与分析
- // extend
- jQuery.fn.extend = jQuery.extend = function() {
- var target = arguments[0] || {}; // target 赋值为第一个参数, 也就是要扩展的对象
- var length = arguments.length; // 获取参数的个数
- var i = 1;
- var deep = false;
- var options, name, copy, src, copyIsArray, clone;
- if(typeof target === 'boolean') { // 当传入第一个参数是 boolean 时
- deep = target; // 把参数 deep 的值设置为 target, 即传入的第一个参数
- target = arguments[1]; // 把 target(需扩展的对象设置为第二个参数)
- i = 2; // i = 2, 以便之后从第三个参数开始遍历
- };
- if(typeof target !== 'object') { // 验证传入的参数为 obj
- target = {};
- };
- if(length === i) { // 如果只有一个参数, 则 extend 方法为 jQuery 内部的扩展
- target = this; // 把 target 的引用设置为 this, 指向 $ 或者 $()
- i--;
- };
- // 浅拷贝
- for( ;i < length; i++) { // boolean 参数和所需要扩展的对象的属性无需遍历
- if((options = arguments[i]) !==null) {
- for(name in options) {
- copy = options[name];
- src = target[name];
- // 如果需要深拷贝, 并且 options 的属性对应的是对象或数组时
- if(deep && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
- if(copyIsArray) {
- copyIsArray = false; //copyIsArray 不重置会影响下一次循环的判断;
- clone = src && jQuery.isArray(src) ? src : [];
- } else {
- clone = src && jQuery.isPlainObject(src) ? src : {};
- }
- target[name] = jQuery.extend(deep, clone, copy);
- } else if(copy !== undefined) {
- target[name] = copy;
- };
- };
- };
- };
- return target;
- }
- jQuery.extend({
- isPlainObject: function(obj) { // 判断传入参数的数据类型是否是 obj
- return toString.call(obj) === '[object Object]'
- },
- isArray: function(arr) { // 判断传入参数的数据类型是否是数组
- return toString.call(arr) === '[object Array]'
- }
- });
来源: http://www.jianshu.com/p/24805db798e0