jQuery总体架构 jQuery使用上的几大特点
$('#id')
函数方式直接生成jQuery对象
$('#id').css().html().hide()
链式调用
关于链式调用,既在函数结尾return this
;
无new函数的实现 下面是一个普通的函数,很显然,会陷入死循环;
1 2 3 4 5 6 var jQuery = function ( ) { return new jQuery(); } jQuery.prototype = { ... }
jQuery
用一个init
函数来代替直接new
函数名的方式,还要考虑到jQuery
中分离作用域:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var jQuery = function ( ) { return new jQuery.prototype.init(); } jQuery.prototype = { constructor : jQuery, init: function () { this .jquery = 1.0 ; return this ; }, jquery: 2.0 , each: function ( ) { console .log('each' ); return this ; } } jQuery().jquery jQuery.prototype.jquery jQuery().each
上面的代码看似运行正常,但是问题出在jQuery().each //error
,访问不到each
函数上。实际上,new jQuery.prototype.init()
返回的是init
这个函数的实例,所以init
函数中的this
就没有意义!如果:
1 2 3 var jq = jQuery();jq.__proto__ === jQuery.prototype; jq.each === jQuery.prototype.each;
如果实现上面的proto的指向问题,原型函数调用问题就解决了,但实际上:
1 2 var jq = jQuery();jq.__proto__ ===jQuery.prototype.init.prototype;
实际上,jq的proto是指向init函数原型的,所以,我们可以把jQuery.prototype.init.prototype = jQuery.prototype
,这个时候,函数调用就顺理成章了,而且使用的都是引用,指向的都是同一个prototype
对象
jQuery内部结构图 jQuery.fn
,实际上是prototype的一个引用,指向jQuery.prototype;
1 2 3 4 5 6 var jQuery = function ( ) { return new jQuery.prototype.init(); } jQuery.fn = jQuery.prototype { ... }
为什么要用fn指向prototype?一个比较中肯的回答:简洁!你不觉得fn比prototype好写多了么 借用网上的一张图:
从图上可以看出,window对象有两个公共的接口,分别是$
和jQuery
:
1 window .jQuery = window .$ = jQuery
jQuery.extend
方法是一个对象拷贝的方法,包括深拷贝
链式调用 实现方式,在没有返回值的原型函数后面添加return this
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var jQuery = function ( ) { return new Jquery.fn.init(); } jQuery.fn = jQuery.prototype = { constructor : jQuery, init: function () { this .jQuery = 3.0 ; return this ; }, each: function ( ) { console .log('each' ); return this ; } } jQuery.fn.init.prototype = jQuery,fn; jQuery().each().each();
extend extend
是jQuery
的一个重要函数,可以对jQuery
本身的属性和方法进行扩张,也可以对原型的属性和方法进行扩展
extend
函数的功能:
如果参数只有一个object
,即表示将这个对象扩展到jQuery的命名空间中,也就是所谓的jQuery
扩展
如果函数接受了多个object
,则表示一种属性拷贝,将后面多个对象的属性全拷贝到第一个对象上,这其中,还包括深拷贝,即非引用拷贝,第一个参数如果是true
,则表示深拷贝。1 2 3 jQuery.extend(target); jQuery.extend(target, obj1, obj2,...); jQuery.extend(true , target, obj1, obj2,...)
以下是jQuery 3
之后的extend函数源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 jQuery.extend = jQuery.fn.extend = function ( ) { var options, name, src, copy, copyIsArray, clone, target = arguments [ 0 ] || {}, i = 1 , length = arguments .length, deep = false ; if ( typeof target === "boolean" ) { deep = target; target = arguments [ i ] || {}; i++; } if ( typeof target !== "object" && !isFunction( target ) ) { target = {}; } if ( i === length ) { target = this ; i--; } for ( ; i < length; i++ ) { if ( ( options = arguments [ i ] ) != null ) { for ( name in options ) { copy = options[ name ]; if ( name === "__proto__" || target === copy ) { continue ; } if ( deep && copy && ( jQuery.isPlainObject( copy ) || ( copyIsArray = Array .isArray( copy ) ) ) ) { src = target[ name ]; if ( copyIsArray && !Array .isArray( src ) ) { clone = []; } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { clone = {}; } else { clone = src; } copyIsArray = false ; target[ name ] = jQuery.extend( deep, clone, copy ); } else if ( copy !== undefined ) { target[ name ] = copy; } } } } return target; };
由extend
衍生的函数 jQuery.isFunction
源码1 2 3 jQuery.ifFunction = function (obj ) { return jQuery.type(obj) === "function" ; }
这个是简单,但是这里是为了引出涉及到的另一个jQuery
函数jQuery.type
,这个函数用于类型判断。
为什么不用原生js的typeof?因为不好用!