第2章 构造jquery对象 8
-
jQuery
对象是一个类数组对象,含有-
连续的整形属性
-
length
属性 -
大量的
jQuery
方法
-
-
2.1 构造函数
jquery()
8jQuery
很有意思的一点是,它的方法定义很强大,会根据不同的参数情况执行不同的功能。构造函数
jQuery()
有 7 种用法。-
2.1.1
jquery( selector [, context] )
9-
用法
- 如果传入一个字符串参数,
jQuery
会检查这个字符串是选择器还是HTML
代码 - 如果是选择器,则遍历文档
- 如果有匹配的元素,返回匹配的封装了匹配的
DOM
元素的jQuery
对象 - 如果没有匹配的元素,则返回一个空的
jQuery
对象
- 如果有匹配的元素,返回匹配的封装了匹配的
- 如果传入一个字符串参数,
-
-
2.1.2
jquery( html [, ownerdocument] )、jquery( html, props )
9- 用法
- 如果传入的参数看起来像一段
HTML
代码,那么jQuery
会尝试创建新的DOM
元素,并创建一个封装了此DOM
元素的jQuery
对象 - 第二个参数
ownerDocument
用于指定创建新DOM
对象的文档对象,如果不传入,则默认为当前文档对象 - 如果
HTML
代码是单独一个标签,那么第二个参数还可以是props
,是一个包含了属性、事件的普通对象,设置新创建元素的属性、事件
- 如果传入的参数看起来像一段
- 用法
-
2.1.3
jquery( element )、jquery( elementarray )
10-
用法
传入一个
DOM
对象或DOM
数组,然后封装这些DOM
为jQuery
对象
-
-
2.1.4
jquery( object )
10-
用法
- 传入一个普通
JavaScript
对象,把该对象封装到jQuery
对象并返回 - 可以方便的实现自定义事件的绑定和触发
- 传入一个普通
-
-
2.1.5
jquery( callback )
11-
用法
DOM ready
事件的回调函数
-
-
2.1.6
jquery( jquery object )
11-
用法
传入一个
jQuery
对象,则返回该对象的一个副本,这个副本与原jQuery
对象引用相同的DOM
元素
-
-
2.1.7
jquery()
11-
用法
- 不传入任何一个参数,则返回一个空的
jQuery
对象 - 可以用来复用
jQuery
对象,例如,创建一个空的jQuery
对象,然后在需要的时候手动修改其中的元素,再调用jQuery
方法,从而避免重复创建jQuery
对象
- 不传入任何一个参数,则返回一个空的
-
-
-
2.2 总体结构 11
(function(window, undefined) { // 构造 jQuery 对象 var jQuery = (function() { var jQuery = function(selector, context) { return new jQuery.fn.init(selector, context, rootjQuery); }; // 一堆局部变量声明 // ... jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function(selector, context, rootjQuery) { } // 一堆原型属性和方法 }; jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() {}; jQuery.extend({ // 一堆静态属性和方法 }); return jQuery; })(); // 工具方法 Utilities // 回调函数列表 Callbacks Object // 异步队列 Defferred Object // 浏览器功能测试 Support // 数据缓存 Data // 队列 Queue // 属性操作 Attributes // 事件系统 Events // 选择器 Sizzle // DOM遍历 Traversing // 样式操作 CSS(计算样式、内联样式) // 异步请求 Ajax // 动画 Effects // 坐标 Offset、尺寸 Dimensions window.jQuery = window.$ = jQuery; })(window);
以上内容,有几个要点:
-
jQuery
的定义部分,为什么要用自调用匿名函数包裹?减少与其他模块的耦合,体现高内聚低耦合的思想
-
jQuery
、jQuery.fn.init
的prototype
都被覆盖了 -
jQuery
、jQuery.fn.init
这两个方法的prototype
都指向了jQuery.prototype
好处是
jQuery
和jQuery.prototype.init
的实例都可以访问构造函数jQuery()
的原型属性和方法。用图表示即:
new jQuery() ---> jQuery.prototype ----> 同一个对象 new jQuery.prototype.init() ---> jQuery.prototype.init.prototype
-
为什么要增加一个函数
jQuery.fn.init
?1、对返回对象的要求:该对象需要能访问
jQuery
原型上的方法和属性。2、一般情况下返回的是
jQuery
的实例,但如果返回的代码是return new jQuery()
,会形成死循环3、因此构建一个新函数,该函数的实例也能访问
jQuery
原型上的方法和属性 -
为什么要在构造函数
jQuery()
内部用运算符new
创建并返回另一个构造函数的实例?创建一个实例的方式是
new
后面跟一个构造函数,如果构造函数有返回值,运算符new
所创建的对象会被丢弃,返回值将作为new
表达式的值jQuery
利用了这一特性,省去了构造函数jQuery()
之前的运算符new
为了书写方便,为构造函数定义了别名
$
-
-
2.3
jquery.fn.init( selector, context, rootjquery )
13构造函数
jquery.fn.init()
负责解析参数selector
和context
的类型,并执行相应的逻辑,返回jquery.fn.init()
的实例。它有12个有效分支-
.2.3.1 12个分支 13
-
2.3.2 源码分析 14
-
2.3.3 小结 21
-
-
2.4
jquery.buildfragment( args, nodes, scripts )
22-
2.4.1 实现原理 22
-
2.4.2 源码分析 22
-
2.4.3 小结 26
-
-
2.5
jquery.clean( elems, context, fragment, scripts )
27-
2.5.1 实现原理 27
-
2.5.2 源码分析 27
-
2.5.3 小结 39
-
-
2.6
jquery.extend()、jquery.fn.extend()
40-
2.6.1 如何使用 40
-
二者是一样的功能:
jQuery.extend = jQuery.fn.extend = function()
也就是说,
jQuery
对象和jQuery
的实例对象都有extend
方法了 -
语法
jQuery.extend([deep],target,object1[,objectN])
jQuery.fn.extend([deep],target,object1[,objectN])
-
参数
-
deep
是可选的布尔值,表示是否进行深度合并(即递归合并),默认是不递归的,即后面参数的属性的会覆盖第一个参数的同名属性。如果是
true
,表示进行深度合并,合并过程是递归的。 -
target
目标对象
-
objectN
源对象,所有源对象的属性都会合并到目标对象
-
如果只有一个参数
那么参数
target
将被忽略,jQuery
或jQuery.fn
被当做目标对象,用这种方式可以在jQuery
或jQuery.fn
上添加新的属性和方法
-
-
-
2.6.2 源码分析 40
-
-
2.7 原型属性和方法 43
以下属性和方法均在下方代码块中定义
jQuery.fn = jQuery.prototype = { 原型属性和方法 }
也就是说,
jQuery
的实例有这些属性和方法-
2.7.1
.selector、.jquery、.length、.size()
44-
源码
selector: '', // 版本号 jquery: '1.7.1', // jQuery 对象中元素的个数,初始化为 0 length: 0, // 同 length,不建议使用 size: function() { return this.length; },
-
selector
-
介绍
当前
jQuery
对象的选择器,主要用来调试,与实际选择器不一定匹配 -
源码
`jquery`: 当前`jQuery`的版本号 `length`:jQuery 对象中元素的个数,初始化为 0 `size`:同 length,不建议使用,因为有函数调用开销
-
-
-
2.7.2
.toarray()、.get( [index] )
45-
toArray
slice = Array.prototype.slice toArray: function() { return slice.call(this, 0); }
小技巧:借鸡下蛋
利用
Array.prototype.slice
方法将jQuery
对象转为数组,形成方法toArray
。slice
方法里的this
,可以是数组,也可以是类数组。 -
get
源码:
return num == null ? this.toArray() ? (num < 0 ? this[this.length + num] : this[num])
这样就可以支持: 1、参数为空;2、下标为负数。
-
-
2.7.3
.each( function(index, element) )、jquery.each( collection, callback (indexinarray, valueofelement) )
46-
.each
-
功能介绍
1、遍历当前
jQuery
对象,并在每个对象上执行回调函数2、回调函数参数是索引(从
0
开始)和当前对象3、最重要的一点是,回调函数中的
this
总是指向当前元素4、在回调函数中返回
false
可以终止遍历 -
实现技巧
在源码中,它通过调用
jQuery.each
方法来实现,又一个借鸡生蛋的应用。
-
-
jQuery.each
- 源码在
627~666
行,就不贴在这里了 - 源码实现的总体思路
- 功能上,可以遍历(类)数组和对象(包括函数)
- 可以自定义回调函数的参数,如果不自定义,则默认给回调函数传
index, element
的参数
- 小技巧
-
判断是否是对象:
isObj == object.length === undefined || jQuery.isFunction(object)
-
遍历对象,用
for in
-
遍历数组,用
for
循环 -
执行、判断写在同一句
if(callback.call(object[i], i, object[i++]) === false){ break; }
-
break
可以跳出for in
和for
循环
-
- 源码在
-
-
2.7.4
.map( callback(index, domelement) )、jquery.map( arrayorobject, callback(value, indexorkey) )
47 -
2.7.5
.pushstack( elements, name, arguments )
49 -
2.7.6
.end()
51-
功能描述
核心代码:
return this.prevObject || this.constructor(null)
如果是:
$(ul.first).find('.foo').css(..).end().find('.bar')
-
-
2.7.7
.eq( index )、.first()、.last()、.slice( start [, end] )
51-
.eq
eq: function(i) { i = +i; return i === -1 ? this.slice(i) : this.slice(i, i + 1); }
小技巧:如果
i
是字符串,把前面加上+
可以把该参数转换为数值
-
-
2.7.8
.push( value, ... )、.sort( [orderfunc] )、.splice( start,deletecount, value, ... )
52-
.push
var foo = $(document); foo.push(document.body); // 2
-
.sort
var foo = $([33, 4, 1111, 222]); foo.sort(); // [1111, 222, 33, 4] foo.sort(function(a, b) { return a - b; }); // [4, 33, 222, 1111]
-
-
2.7.9 小结 53
-
-
2.8 静态属性和方法 54
-
2.8.1
jquery.noconflict( [removeall] )
55看源码即可,绕来绕去的
-
2.8.2 类型检测:
jquery.isfunction( obj )
、jquery.isarray( obj )
、jquery.iswindow( obj )
、jquery.isnumeric( value )
、jquery.type( obj )
、jquery.isplainobject( object )
、jquery.isemptyobject( object )
56- 判断类型
核心代码是用了
toString.call(obj)
判断,该表达式的值是:[object Array]
、[object Boolean]
、[object Date]
、[object Function]
、[object Number]
、[object Object]
、[object RegExp]
、[object String]
还有一个小技巧,循环数组:
('Boolean Date Function Number Object RegExp String').split(' ')
-
isWindow
判断方法是:
obj == obj.window
,以前的版本里是:setInterval in obj
-
jquery.isplainobject( object )
-
功能
判断对象是否由
{}
或new Object()
创建 -
返回
false
的情况-
object
可以转为false
-
Object.prototype.toString.call(object)
返回的不是[object Object]
-
object
是DOM
元素object.nodeType
非空 -
object
是window
对象 -
不是由
Object()
函数创建,而是由自定义函数创建的,返回false
-
含有属性
constructor
是继承属性
是自身属性
如果不含属性
constructor
,则一定是{}
创建的对象 -
没有属性
isPropertyOf
isPropertyOf
是Object
原型对象的特有属性 -
执行时抛出异常。
IE 8/9
中,在某些浏览器对象上执行以上检测时会抛出异常,也应该返回false
-
-
-
返回
true
的情况用
Object.prototype.hasOwnProperty(property)
检测对象是否含有该非继承属性如果该对象没有属性,或所有属性都是非继承属性,则返回
true
-
-
jquery.isemptyobject( object )
用
for in
遍历自身属性和继承属性 -
parseFloat(x)
可以解析字符串,并返回字符串的第一个数字;如果没有数字,则返回NaN
;如果参数是对象,则自动调用该对象的方法toString()
,得到该对象的字符串表示,然后再解析
-
2.8.3 解析
json
和xml
:jquery.parsejson( data )
、jquery.parsexml( data )
60-
jquery.parsejson( data )
-
解析思路
先尝试用
JSON.parse
解析,如果没有该方法,则用(new Function('return' + data))()
解析其余的是正则表达式匹配字符串之类的东西,在此略过
-
JSON.parse
解析
json
字符串为json
对象判断方法:
window.JSON && window.JSON.parse
-
JSON.stringify
解析
json
对象为json
字符串用法1:
JSON.stringify({a: 1, b: 2}); // '{"a": 1, "b": 2}'
用法2:
JSON.stringify({a: 1, b: 2}, function(key, value) { if(key == '') return value; if(key == 'a') return value * 10; if(key == 'b') return undefined; return value; }) // '{"a": 10}'
用法3:
JSON.stringify({a: 1, b: 2}, ['b']); // '{"b": 2}'
用法4:
JSON.stringify({a: 1, b: 2}, null, 4); // '{ "a": 1 "b": 2 }'
-
-
-
2.8.4
jquery.globaleval( code )
65略
-
2.8.5
jquery.camelcase( string )
65针对
-ms
单独做了处理,所有处理函数还是很简洁的return string.replace(/^-ms-/, 'ms-').replace(/-[a-z]|[0-9]/, function(){...});
-
2.8.6
jquery.nodename( elem, name )
66dom
元素的节点名称:dom.nodeName
-
2.8.7
jquery.trim( str )
67书中的思路很清晰,值得一提的是,这个方法里同样用了
String.prototype.trim()
方法来借鸡生蛋另外,在
IE9
中,正则/s/
不能匹配不间断空格xA0
,但其也被认为是空格。测试是否不识别,用:/S/.test('xA0')
,如果是true
,则不能识别 -
2.8.8 数组操作方法:
jquery.makearray( obj )、jquery.inarray( value, array [, fromindex] )、jquery.merge( first, second )、jquery.grep( array, function(elementofarray, indexinarray) [, invert] )
68-
jquery.makearray( obj )
学到了一点:
push
方法里的this
可以指定为类数组 -
jquery.inarray( value, array [, fromindex] )
fromIndex
是查找的起点如果浏览器支持数组方法
indexOf
,则直接调用,否则就自己写方法数组的下标有可能是不连续的,所以需要用
i in array
来判断是否存在下标i
值得学习的就是判断了
if($.inArray(element, array) > -1) {}
太繁琐,改进为
if(!!~$.inArray(element, array)) {}
~
按位取反,相当于改变符号并且减一,只有当-1
时,~(-1) == 0
!!
用来形成布尔值 -
jquery.merge( first, second )
这个方法的源码写的挺不错的,值得一看。
其中,把
second
认为两种对象处理:1、数组/类数组(判断依据:有无整数/可转为整数的属性
length
,typeof second.length === 'number'
)2、含有连续整形(或可转换为连续整形)的对象,如
{0: 'a', 1: 'b'}
,从下标0
开始遍历。最后修正
first.length
,因为first
不一定是真正的属性,需要手动维护length
属性。
-
-
2.8.9
jquery.guid、jquery.proxy( function, context )
72-
jquery.proxy( function, context )
这个函数使得某个函数在任何环境下执行时,上下文都是
context
,很实用。而且,它的实现原理是:1、闭包封存上下文
context
;2、返回一个新函数,新函数的作用域链上,有闭包内的上下文context
其他的,看源码即可。
-
-
2.8.10
jquery.access( elems, key, value, exec, fn( elem, key, value ), pass )
74 -
2.8.11
jquery.error( message )
、jquery.noop()
、jquery.now()
75略
-
2.8.12 浏览器嗅探:
jquery.uamatch( ua )
、jquery.browser
76略
-
2.8.13 小结 77
-
-
2.9 总结 77
到这一步,值得将
jQuery
的整体结构再回顾一遍了。代码概述在11
页的图上。(1)构造函数
jQuery()
有7种用法,根据参数的不同而不同。(2)
jQuery.fn.init()
方法有12
种用法,根据参数的不同而不同。(2)原型属性和方法,直接放在
jQuery.fn = jQuery.prototype
对象上(3)静态属性和方法,通过
jQuery.extend({...})
放在jQuery
对象上