您的位置:首页 > Web前端 > JQuery

jQuery 1.6 源码学习(六)——core.js[6]之jQuery对象/数组操作相关方法

2012-02-08 15:13 986 查看
本文将分析jQuery对象操作相关方法(包括静态和实例方法):

merge方法,代码如下:

//此方法用于合并两个jQuery对象(因为jQuery对象中有length属性)或者数组,
//这个方法非常简单,就是简单的追加第二个对象的属性到第一个对象上去
merge: function( first, second ) {
var i = first.length,
j = 0;
if ( typeof second.length === "number" ) {
for ( var l = second.length; j < l; j++ ) {
first[ i++ ] = second[ j ];
}

} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
}

first.length = i;

return first;
},

可以看到此方法非常简单,但它在jQuery内部应用的地方却是非常多的,包括init方法,pushStack方法,makeArray方法里都用到了此方法。

pushStack方法,代码如下:

pushStack: function( elems, name, selector ) {
//constructor指向jQuery方法本身,那自然ret会被创建为一个空的jQuery对象(可作为一个元素集)
//此时等效为 var ret = jQuery();
// Build a new jQuery matched element set
var ret = this.constructor();

if ( jQuery.isArray( elems ) ) {
//push是Array.prototype.push的一个shortcut,此时将elems添加到ret中
push.apply( ret, elems );

} else {
jQuery.merge( ret, elems );
}
// 保存操作前的对象
// Add the old object onto the stack (as a reference)
ret.prevObject = this;

ret.context = this.context;

if ( name === "find" ) {
ret.selector = this.selector + (this.selector ? " " : "") + selector;
} else if ( name ) {
ret.selector = this.selector + "." + name + "(" + selector + ")";
}

// Return the newly-formed element set
return ret;
},

要注意的是pushStack方法并不对源对象做破坏性更改(所谓破坏性更改,是指对原jQuery对象中选择的元素有变动的更改),而是返回新的 jQuery对象,因此在使用时需要注意。也就是说诸如下面的代码在使用时容易使人迷惑,其实obj并未把DOM元素加入到当前的jQuery栈,而我们 将元素加入当前jQuery栈的一般做法还是用选择器来实现:

var obj = $("a");
ret = obj.pushStack(document.getElementsByTagName("span")).pushStack(document.getElementsByTagName("input"));
//obj依然是包含a元素的jQuery对象
console.log(obj); //[<a>?</a>?]
//ret则仅仅包含input
console.log(ret); //[<input type=?"button" id=?"btn" value=?"click!">?]

之所以把pushStack设置为实例方法而非静态方法,就是为了在jQuery中实现一个undo操作的功能,更多可以参见jQuery文档中关于end方法的使用。

其实pushStack本身在jQuery文档中也未公开,作为Internals方法存在,因此不建议使用此方法,但是在jQuery内部经常看到此方法出现,比如下面即将说到的map方法:

//该方法将返回经过callback过滤后的jQuery对象,
map: function( callback ) {
return this.pushStack( jQuery.map(this, function( elem, i ) {
return callback.call( elem, i, elem );
}));
},

由于实例map方法调用了静态map方法,我们接着看看静态map方法:

// arg is for internal usage only
map: function( elems, callback, arg ) {
var value, key, ret = [],
i = 0,
length = elems.length,
// 传入jQuery对象时,将会把jQuery对象也作为数组来处理
// jquery objects are treated as arrays
isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;

// Go through the array, translating each of the items to their
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg );//必须有返回值

if ( value != null ) {
ret[ ret.length ] = value;
}
}

// Go through every key on the object,
} else {
for ( key in elems ) {
value = callback( elems[ key ], key, arg );

if ( value != null ) {
ret[ ret.length ] = value;
}
}
}
// 最后连接数组,这样做是为了防止空项出现
// Flatten any nested arrays
return ret.concat.apply( [], ret );
},

map方法和each方法非常的相似,其区别在于,map提供了一个数组到另一个数组映射的功能,而each则单纯地队对象或数组是进行迭代访问,这要求我们必须在使用map时,回调函数必须提供返回值,否则将在返回值中删除该项。

另一个容易混淆的数组遍历方法是grep:

grep: function( elems, callback, inv ) {
var ret = [], retVal;
inv = !!inv;  //小提示,!!是为了确保inv转换为bool值,当不传递inv时,!!undefined便等于false

// Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, length = elems.length; i < length; i++ ) {
retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {//默认回调函数返回false时将不保留此项
ret.push( elems[ i ] );
}
}

return ret;
},

很容易知道我们在迭代数组时,必须要求回调函数中返回一个bool值来确定该项是否保留。

grep和map方法在文档中属于实用工具(Utilities),由于概念相近,因此放在这里讲解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐