jQuery中的isArrayLike函数

测试代码1:

var obj={name:"xx",sex:"female",length:"xx"}
    alert("length" in obj && obj.length);//第一个是true,所以返回第二个值,第二个值就是xx
alert("结果是=>"+"length" in obj && obj.length);//第一个是变成"结果是=>length in obj"显然直接是false(和+在一起,变成了字符串连接),所以&&操作符就直接返回false
alert("结果是:"+("length" in obj && obj.length));//把后面的结果先计算,打上括号就能够得到正确的结果!
 alert(isArraylike(obj));//返回false,因为length不是0,也不是number类型
var obj={name:"xx",sex:"female",length:"2"}
var obj1={name:"xx",sex:"female",length:0}
alert(typeof("length" in obj && obj.length));//虽然在对象obj里面,length没有打上双引号,但是“length” in obj是正确的,同时obj.length是string类型
alert(isArraylike(obj1));//因为obj1的length是0返回true
alert(isArraylike(obj));//因为obj的length是string类型,直接返回false

测试代码2:

//测试jquery对象,length直接为number
alert("jquery对象"+isArraylike($("input")));
alert("length" in $("input") && $("input").length)
<div id="div1">
<input type="text" id="input1"/>
<input type="text" class="input1"/>
<input type="text" class="input1"/>
</div>
alert("结果是:"+document.getElementById("div1").nodeType);//返回1,元素为1,属性为2,文本是3,document是9,documentFragment是11

测试代码3:

var obj={name:"xx",length:0}
     alert(isArraylike(obj))//返回true
     var obj={name:"xx",length:-5}
     alert(isArraylike(obj))//false

测试代码4:

 var obj={name:"qin",sex:"female",length:5}
  alert(isArraylike(obj));//返回false,因为,虽然length是number类型,同时length>0,但是(length-1) in obj返回false,var obj={name:"qin",sex:"female",n:"xx",m:"xx",y:"xx",length:5}也就是一样的道理。
var obj={0:"qin",1:"female",2:"xx",3:"xx",4:"xx",length:5}//返回结果就是true,因为(4-1) in obj是返回true的

测试代码5:

//如果是Element元素,也就是nodeType===1,而且含有length属性
//alert("结果是1:"+document.getElementById("div1").length);是undefined,也就是没有length属性
//document.getElementById("xx")返回的nodeType是1,但是没有length属性
//document.getElementsByTagName("div")的集合有length属性,但是没有nodeType,返回的是htmlCollection集合

测试总结:三种情况下返回true。第一种:length恒等于0;第二种:本身就是Array类型;第三种:length>0,同时length是number类型,同时(length-1) in obj为true!

isArrayLike函数源码:‘

function isArraylike( obj ) {
var length = "length" in obj && obj.length,
type = jQuery.type( obj );
//如果是函数,或者window那么直接返回false
if ( type === "function" || jQuery.isWindow( obj ) ) {
return false;
}
if ( obj.nodeType === 1 && length ) {
return true;
}
return type === "array" || length === 0 ||
     //length是数字类型,同时length>0而且length-1要存在
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}

总结:如果是函数或者window对象,那么直接是false;如果是数组那么返回true;如果有length并且length是0返回true;如果length是number同时length>0同时length-1在obj里面那么返回true!什么时候nodeType是1,同时也具有length属性呢:

var div=$("#content")[0];
div.length=1;//isArrayLike检测返回true

同时所有的jQuery对象都是类数组对象:

isArraylike($("#content"))//打印true

那么为什么要对上面length=0进行单独的判断呢,请看下面:

function Test()
{
	alert(isArraylike(arguments));
}
Test();//这时候如果没有length===0那么就会返回false表示不是类数组,因此这里我们对这种情况单独判断!

以下是补充内容,有兴趣的可以阅读一下:

(1)这里之所以要判断(length-1) in obj是引入了稀疏数组的概念,稀疏数组在用forEach或者map迭代的时候会跳过空隙(这两个方法第一个参数是元素,第二个参数是下标,第三个是调用数组),也就是要确保数组的最后一个元素是存在的!如果要创建密集数组可以通过Array.apply(arr,Array(3))的方式,于是forEach和map就不会跳过其中的元素了!

(2)我们在上面那一篇讲稀疏数组的博客中看到了bind方法,bind方法的调用者是一个函数,传入的第一个参数是调用函数中this的指向,当然也可以传递额外的参数,这些额外的参数会作为原来绑定的那个函数的前几个参数,从而新函数传递的参数成为后面的参数。返回值是一个函数,这个函数除了参数和this指向不同以外和原来的函数是相同的,虽然是通过新函数调用的,但是arguments.callee仍然是原来的函数。
(3)通过把函数保存到本地,这种方式会改变函数中this的指向,进而导致产生错误,因为有时候内置的方法往往属于特定的对象,于是这时候要么用bind方法,要么用call或者apply方法修改this的指向从而执行特定对象的方法!

(4)我们下面给出一个js中map方法的案例:

var arr=[1,2,3];
function f(elem,index,arr){
//this就是map传入的第二个参数,一直就是12,不会变化!
	alert(this);
	return elem*2;
}
//打印[2,4,6]
alert(arr.map(f,12));
//输出第二个参数[0,1,2]
alert([4,5,6].map(Function.prototype.call.bind(Number)));
var a = ["aaa  ", "  bbb", "  ccc  "]
//打印[AAA,BBB,CCC],这个call方法的this指定的是String.prototype.toUpperCase
var result=a.map(Function.prototype.call, String.prototype.toUpperCase); 
alert(result);
//打印[aaa,bbb,ccc]表示已经去除了两端的空格了!必须要指定map第二个参数!
var result=a.map(Function.prototype.call, String.prototype.trim); 
alert(result);
//TypeError说a.map不是一个函数!,也就是这个Function.prototype.call没有指定this
//而call方法的第一个参数必须是this!
var result1=a.map(Function.prototype.call);

上一篇:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

昵称 *