在JavaScript中,除了5种原始数据类型之外,其他所有的都是对象,包括函数(Function)。

基本数据类型:String,boolean,Number,Undefined, Null

引用数据类型:Object(Array,Date,RegExp,Function)

在这个前提下,咱们再来讨论JavaScript的对象。

1、创建对象

var obj = {}; //种方式创建对象,被称之为对象直接量(Object Literal)
var obj = new Object(); // 创建一个空对象,和{}一样

更多创建对象的知识,参见《JavaScript权威指南(第6版)》第6章

2、创建数组

var arr = [];//这是使用数组直接量(Array Literal)创建数组
var arr = new Array();//构造函数Array() 创建数组对象

更多创建数组的知识,参见《JavaScript权威指南(第6版)》第7章。

3、对象与数组的关系

在说区别之前,需要先提到另外一个知识,就是JavaScript的原型继承。所有JavaScript的内置构造函数都是继承自 Object.prototype。在这个前提下,可以理解为使用 new Array() 或 [] 创建出来的数组对象,都会拥有 Object.prototype 的属性值。

对于题主的问题意味着:

var obj = {};// 拥有Object.prototype的属性值
var arr = [];
//使用数组直接量创建的数组,由于Array.prototype的属性继承自 Object.prototype,
//那么,它将同时拥有Array.prototype和Object.prototype的属性值

可以得到对象和数组的第一个区别:对象没有数组Array.prototype的属性值

4、什么是数组

数组具有一个最基本特征:索引,这是对象所没有的,下面来看一段代码:

var obj = {};
var arr = []; obj[2] = 'a';
arr[2] = 'a'; console.log(obj[2]); // 输出 a
console.log(arr[2]); // 输出 a
console.log(obj.length); // 输出 undefined
console.log(arr.length); // 输出 3

通过上面这个测试,可以看到,虽然 obj[2]与arr[2] 都输出'a',但是,在输出length上有明显的差异,这是为什么呢?

obj[2]与arr[2]的区别

  • obj[2]输出'a',是因为对象就是普通的键值对存取数据

  • 而arr[2]输出'a' 则不同,数组是通过索引来存取数据,arr[2]之所以输出'a',是因为数组arr索引2的位置已经存储了数据

obj.length与arr.length的区别

  • obj.length并不具有数组的特性,并且obj没有保存属性length,那么自然就会输出undefined

  • 而对于数组来说,length是数组的一个内置属性,数组会根据索引长度来更改length的值。

为什么arr.length输出3,而不是1呢?

  • 这是由于数组的特殊实现机制,对于普通的数组,如果它的索引是从0开始连续的,那么length的值就会等于数组中元素个数

  • 而对于上面例子中arr,在给数组添加元素时,并没有按照连续的索引添加,所以导致数组的索引不连续,那么就导致索引长度大于元素个数,那么我们称之为稀疏数组。

有关稀疏数组的特性就不再讨论更多,参见《JavaScript权威指南(第6版)》7.3节。

5、伪数组

定义:

1、拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理,这里你可以当做是个非负整数串来理解)
2、不具有数组所具有的方法

伪数组,就是像数组一样有 length 属性,也有 0123 等属性的对象,看起来就像数组一样,但不是数组,比如

var fakeArray = {
length: 3,
"0": "first",
"1": "second",
"2": "third"
}; for (var i = 0; i < fakeArray.length; i++) {
console.log(fakeArray[i]);
} Array.prototype.join.call(fakeArray,'+');

常见的参数的参数 arguments,DOM 对象列表(比如通过 document.getElementsByTags 得到的列表),jQuery 对象(比如 $("div"))。

伪数组是一个 Object,而真实的数组是一个 Array

fakeArray instanceof Array === false;
Object.prototype.toString.call(fakeArray) === "[object Object]"; var arr = [1,2,3,4,6];
arr instanceof Array === true;
Object.prototype.toString.call(arr) === "[object Array]"

《javascript权威指南》上给出了代码用来判断一个对象是否属于“类数组”。如下:

// Determine if o is an array-like object.
// Strings and functions have numeric length properties, but are
// excluded by the typeof test. In client-side JavaScript, DOM text
// nodes have a numeric length property, and may need to be excluded
// with an additional o.nodeType != 3 test.
function isArrayLike(o) {
if (o && // o is not null, undefined, etc.
typeof o === 'object' && // o is an object
isFinite(o.length) && // o.length is a finite number
o.length >= 0 && // o.length is non-negative
o.length===Math.floor(o.length) && // o.length is an integer
o.length < 4294967296) // o.length < 2^32
return true; // Then o is array-like
else
return false; // Otherwise it is not
}

不过有个更简单的办法来判断,用 Array.isArray

Array.isArray(fakeArray) === false;
Array.isArray(arr) === true;

从外观上看伪数组,看不出来它与数组的区别,在JavaScript内置对象中常见的伪数组就是大名鼎鼎的auguments:

(function() {
console.log(typeof arguments); // 输出 object,它并不是一个数组
}());

另外在DOM对象中,childNodes也是伪数组

console.log(typeof document.body.childNodes); // 输出 object

除此之外,还有很多常用的伪数组,就不一一列举。

伪数组存在的意义,是可以让普通的对象也能正常使用数组的很多算法,比如:

var arr = Array.prototype.slice.call(arguments)

或者
var arr = Array.prototype.slice.call(arguments, 0); // 将arguments对象转换成一个真正的数组 Array.prototype.forEach.call(arguments, function(v) {
// 循环arguments对象
});

除了使用 Array.prototype.slice.call(arguments),你也可以简单的使用[].slice.call(arguments) 来代替。另外,你可以使用 bind 来简化该过程。

var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice); function list() {
return slice(arguments);
} var list1 = list(1, 2, 3); // [1, 2, 3]

将具有length属性的对象转换成数组对象,arguments是每个函数在运行的时候自动获得的一个近似数组的对象(传入函数的参数从0开始按数字排列,而且有length)。

比如当你 func('a', 'b', 'c') 的时候,func里面获得的arguments[0] 是 'a',arguments[1] 是 'b',依次类推。但问题在于这个arguments对象其实并不是Array,所以没有slice方法。Array.prototype.slice.call( )可以间接对其实现slice的效果,而且返回的结果是真正的Array

对于IE9以前的版本(DOM实现基于COM),我们可以使用makeArray来实现。

// 伪数组转化成数组
var makeArray = function(obj) {
if (!obj || obj.length === 0) {
return [];
}
// 非伪类对象,直接返回最好
if (!obj.length) {
return obj;
}
// 针对IE8以前 DOM的COM实现
try {
return [].slice.call(obj);
} catch (e) {
var i = 0,
j = obj.length,
res = [];
for (; i < j; i++) {
res.push(obj[i]);
}
return res;
} };

更多关于伪数组的知识,参见《JavaScript权威指南(第6版)》7.11节。

6、总结

  • 对象没有数组Array.prototype的属性值,类型是Object,而数组类型是Array;

  • 数组是基于索引的实现,length会自动更新,而对象是键值对;

  • 使用对象可以创建伪数组,伪数组可以正常使用数组的大部分方法;

JavaScript中的数组与伪数组的区别的更多相关文章

  1. JavaScript数组和伪数组

    伪数组和数组 记住一句话: 伪数组是一个Object,数组是Array. 对象和数组之间的关系 JavaScript的内置函数继承与 Object.prototype. 可以认为new Array() ...

  2. JS高级---数组和伪数组

    数组和伪数组  伪数组和数组的区别 真数组的长度是可变的 伪数组的长度不可变 function f1() { var sum = 0; for (var i = 0; i < arguments ...

  3. javascript中apply、call和bind的区别,容量理解,值得转!

    a)  javascript中apply.call和bind的区别:http://www.cnblogs.com/cosiray/p/4512969.html b)  深入浅出 妙用Javascrip ...

  4. javascript中三目运算符和if else有什么区别

    javascript中三目运算符和if else有什么区别今天写了一个图片轮播的小demo,用到了判断先试了一下if else,代码如下:if(n >= count-1){n =0;}else{ ...

  5. JavaScript中var和this定义变量的区别

    JavaScript中var和this定义变量的区别 在js中声明变量时可以使用var和this,但使用this的有很大一部分参考书是没有的,经过查阅相关资料总结如下: 用var和this声明变量,存 ...

  6. javascript中back(-1)和go(-1)的区别

    javascript中back(-1)和go(-1)的区别 一.总结 一句话总结: 数据 history.back(-1):直接返回当前页的上一页,数据全部消息,是个新页面 history.go(-1 ...

  7. JavaScript中基本数据类型和引用数据类型的区别(栈——堆)

    JavaScript中基本数据类型和引用数据类型的区别 1.基本数据类型和引用数据类型 ECMAScript包括两个不同类型的值:基本数据类型和引用数据类型. 基本数据类型指的是简单的数据段,引用数据 ...

  8. 掌握javascript中的最基础数据结构-----数组

    这是一篇<数据结构与算法javascript描述>的读书笔记.主要梳理了关于数组的知识.部分内容及源码来自原作. 书中第一章介绍了如何配置javascript运行环境:javascript ...

  9. javascript中对象字面量与数组字面量

    第一部分 我们知道JavaScript中的数据类型有基本数据类型和引用类型,其中Object类型就是非常常用的类型.那么如果创建一个Object类型的实例呢?下面我介绍两种方法: 第一:构造函数法. ...

随机推荐

  1. sql查询前后两位

    SQL排名的问题,A这个人在数据库里排第十,怎么查询一个他前面两位,后面两位,包括自己的五条数据,各位有啥高招? DECLARE @table TABLE ( id INT PRIMARY KEY , ...

  2. Python3.6学习笔记(五)

    网络编程 网络程序出现的比互联网要早很多,实现方式主要依靠网络上不同主机间进程的通信,通信协议最重要的是TCP/IP协议.在这两个协议基础上还有很多更高级的协议,包括HTTP.SMTP等.要进行两个主 ...

  3. Top N的MapReduce程序MapReduce for Top N items

    In this post we'll see how to count the top-n items of a dataset; we'll again use the flatland book ...

  4. Matlab注释多行和取消多行注释的快捷键

    matlab里注释符号是%,只是单行注释,可是没有多行注释符号,就像C/C++/Java中都有多行注释符号/*  */. 如果利用单行注释的方式手工注释一段程序会很麻烦,matlab软件自带快捷键支持 ...

  5. C++用iconv进行页面字符转换

    在对HTML页面进行爬取时,总会遇到一些不同的编码,而我们通常都不会一一对这些编码进行处理,而是集体转换成相同的编码,也易于装入数据库.此时,iconv便成为一个很方便的工具. iconv 头文件&q ...

  6. [置顶] think in java interview-高级开发人员面试宝典(一)

    “生死六重门” 无论你是在职,非在职,高级工程师,工程师,架构师,如果你正在面试阶段,请看完此文! 相信这篇文章对你的职业生涯和阶值观会造成重大的改变! 如果你是一名PM或者是管理者正在物色合适的开发 ...

  7. python部分重点底层源码剖析

    Python源码剖析—Set容器(hashtable实现) python源码剖析(内存管理和垃圾回收)

  8. DialogPlus

    项目地址:https://github.com/orhanobut/dialogplus  Demo地址:https://github.com/baiqiantao/DialogPlusTest co ...

  9. idea丢失svn解决办法

    今天打开Idea,习惯用ctrl+t来更新svn,杯具出现了,快捷键失效了,我觉得可能是其他的什么软件占用了这个快捷键,于是把qq,微信,rtx,各种软件都关掉,发现还是不好使,于是重启了一下,发现还 ...

  10. VM虚拟机Failed to initialize remote display subsystem怎么办

    1 如图所示,启动虚拟机的时候出现提示Failed to initialize remote display subsystem.怎么办 2 进入DOS窗口,输入net user __vmware_u ...