码迷,mamicode.com
首页 > 编程语言 > 详细

JavaScript——引用类型之数组

时间:2015-04-28 22:40:23      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:

前言

之前本菜打算在写完基本类型后写引用类型Object的,因为Object是引用类型的基础,其他的引用类型也是以Object为根本。只是关于对象的基本认识与简单操作确实可写的不多,打算之后与原型、原型链一起写。本博将介绍引用类型Array,即JavaScript中的数组。

Array

首先数组到底是什么呢?数组是一段线性分配的内存,它能通过整数计算偏移并访问其中的元素。遗憾的是这个定义是指其他语言中的数组,JavaScript中并没有此类数据结构。作为替代,JavaScript中基于对象创建了一种类数组的结构,它把数组的下标转换成字符串当作属性。这种结构虽然效率不如真正的数组,但它更加方便、灵活、强大。同时JavaScript的Array类型也是除了Object以外使用最多的。

申明

JavaScript的数组有两种申明方式:

1.Array()构造函数

2.数组字面量

Array() 构造函数

使用new操作符调用Array构造函数,完成数组的实例化。

var myArr = new Array();

在使用Array()构造函数创建新数组时也可以传入参数,具体有以下几种方式:

1).一个参数

当传入的参数是数值时,生成一个length属性为该值的数组。

当传入的参数不是数值时,则生成一个包含该值且length为1的数组。 

2).多个参数

生成一个包含全部参数值的数组。

var arr1 = new Array(3), //[]
    arr2 = new Array("3"), //["3"]
    arr3 = new Array(‘red‘,‘green‘,‘blue‘); //["red","green","blue"]

alert(arr1.length); //3
alert(arr1.length); //1
alert(arr1.length); //3

这里要特别注意一点,我之所以没有简单的把length简单的说成是"长度",因为JavaScript数组的length属性严格上来说不应该完全理解为"长度",这一点之后我会解释的。

数组字面量 

var arr = [1,3,5,7,9];

这种申明方式也是最常用的,它的书写方式更加简洁、直观。

特点

JavaScript的数组有什么特点呢,或者说它其他语言的数组有什么不同呢?

1.最特别的一点,JavaScript数组的每一项都可以保存不同的数据类型。

var myArr = [1,"hello",null,undefined,{"age":"Lily"},false]; 

技术分享

如此看来JavaScript数组确实强大,它不仅可以保存不同类型的值,并且同一个数组中每一项的类型都可以不同。

同时,也可以通过下标索引修改数组中的项

myArr[3] = "xxx"; //[1,"hello",null,"xxx",Object,false]

2.JavaScript数组的length属性是动态可变的,包括隐式与显式的改变方式。

隐式是指通过向数组中添加值来"撑大"数组,而显式即为直接设置数组的length属性。由于length属性的特别,接下来详细介绍下。

length属性

由于JavaScript中数组是基于对象创建的,所以length并不完全代表其长度,应该理解为Array这个对象的一个属性。怎么理解呢,例子如下。

我将之前申明的数组myArr在控制台打印出来:

技术分享

从图中我们可以很清楚地看出数组即对象这个道理,所谓的索引下标实际为对象中的属性,只是这些属性是以连续的数值命名的。接着往下看,我们看到了与索引属性并列的length属性,以及对象特有的_proto_属性(该属性和对象的原型密切相关,以后我们会讨论)。

该数组我们甚至可以简单的理解为创建了如下对象:

var myArr = {
      "0": 1,
      "1": "hello",
      "2": null,
      "3": undefined,
      "4": {"age":"Lily"},
      "5": false,
      "length": 6
      .
      .
}    

有人会说讨论这个有意义吗?length值确实代表数组长度啊。那我们通过了解如何显式地改变length值来讨论这个问题。

JavaScript数组的length属性并不是只读的,当我们将length变小时,多出的项会被自动截掉。

myArr.length = 3;
console.log(myArr); //[1,"hello",null]

当我们将length值设大时,而之前问题的答案就呼之欲出了。

myArr.length = 100;

 

技术分享

从结果图中我们可以看出,虽然我们将length值增大到100,但显示出来的数组依然只有初始化时的6项,改变的仅仅是数组这个“对象”的某一个属性值。

再看一个例子,如果我们初始化一个空数组,然后增大其属性值:

var myArr1 = new Array();
myArr1.length = 100;

技术分享

可以看到即使增大了length属性,它依然是个空数组。

《JavaScript高级程序》中曾说过,当我们将数组的值变大时,未初始化的项会自动用undefined值来填充。它的意思是什么呢?

var myArr2 = [1,2,3];
myArr2.length = 5;
console.log(myArr2); //伪[1,2,3,undefined,undefined]
console.log(myArr2[3]); //undefined

它意为当length属性增大时,数组的项数也会同时增加,只是增加项的内容为undefined值。但从上面两个例子我们可以看出事实并不如此,索引下标没有增加,改变的只是length属性的值。

当执行上例中第四行代码打印myArr2数组中第四项时,结果为undefined。这并不意味着第四项保存着undefined值,而是根本没有第四项。回想一下,当我们检索一个对象中不存在的属性时,返回的不也是undefined吗?就是这个道理!

那么我们认证了这么多为的是什么?

1.数组的下标不随length属性的变大而自增

2.因为下标即属性这个道理,当有人为干预时它们很可能是不连续的!

明白以上两点,为的就是在运用之后数组内置方法时减少错误的发生。这个问题我也是在看某位大神博客中的例子发现的,理解之后我便提醒自己数组的length和长度并不完全是一回事。

常用方法

由于JavaScript数组的方法很多,这里尽量用最精练的语言一一介绍。

检测

检测一个变量是不是数组有以下两种方法:

1.instanceof操作符,用来检测值究竟是哪种引用类型的实例。

var arr = [1,2,3],
    value = arr instanceof Array;
alert(value); //true

2.Array.isArray()方法。由于instanceof操作符假定单一的全局环境,为了满足多个窗口的情况ECMAScript5新增了该方法。

var arr = [1,2,3],
    value = Array.isArray(arr);
alert(value); //true

join()方法

以指定字符做连接字符,依次连接数组中的项并返回构成的字符串。在不传入参数或者传入参数为undefined时以","拼接。

var colorArr = ["red","green","blue"];
alert(colorArr.join()); //red,green,blue
alert(colorArr.join(undefined)); //red,green,blue
alert(colorArr.join("*")); //red*green*blue

栈与队列方法

首先说栈方法,“后进先出”。push()方法为数组末尾添加若干项并返回新数组长度,pop()方法从数组末尾取出一项,并返回取出的项。

var colorArr = ["yellow","orange"],
    count = colorArr.push("white","black");
alert(count); //4

var item = colorArr.pop();
alert(item); //black

列方法,“先进先出”。shift()方法从数组开头取出一项,并返回该项。配合push()方法可以实现数组的队列操作。

var colorArr = ["yellow","orange"],
    count = colorArr.push("white","black");
alert(count); //4

var item = colorArr.shift();
alert(item); //yellow

unshift()方法,与push()方法类似。只不过是从数组开头添加若干项,并返回新数组长度。搭配pop()方法可以实现数组的反向队列操作。所说unshift()方法效率较数组其他方法不高,所以实际中还是慎用。

var colorArr = ["yellow","orange"],
    count = colorArr.unshift("red","green","blue");
alert(count); //5

var item = colorArr.pop();
alert(item); //orange

栈与队列方法中这些方法的返回值该怎么记呢?有个小技巧,如果是往数组中添加项的操作,返回的就是新数组的长度。如果是从数组中取出项的操作,那返回的就是被取出的项。是不是很好记呢?

排序方法

reverse()方法,将数组反转排序。直观但不够奶灵活。 

var numArr = [1,2,3,4,5,6];
numArr.reverse();
alert(numArr); //6,5,4,3,2,1

sort()方法,用于将数组按照某种顺序排列,比如递增或递减。

var numArr = [1,22,3,2,26];
numArr.sort();
alert(numArr); //1,2,22,26,3

从上例看出sort()方法并没有按照我们预想的进行排序,这是由于sort()方法在默认情况下是调用数组中每一项的toString()方法,也就是说实际比较的并不是数字而是字符串,所以才会得不到想要的结果。

为了使其能按照预想的方式进行排序需要传入比较函数:

function compare(value1, value2) {
    if (value1 < value2) {
        return -1;
    } else if (value1 > value2) {
      return 1;
    } else {
        return 0;
    }
}    

比较函数接收两个参数。比较规则大概如下:当希望value1位于value2之前则返回一个负数,希望value1位于value2之后则返回一个正数,相等返回0。

var numArr = [1,22,3,2,26];
numArr.sort();
alert(numArr); //1,2,3,22,26

上面的比较函数可以比较大多数数据类型,如果要比较的只是数值的话可以使用简化版的比较函数。

function compareS(value1, value2) {
  return value1 - value2;          
}    

当然以上例子均是升序排列,降序只需调换函数中两个参数的位置即可。

操作方法

数组的操作类方法主要有三个,splice()concat()以及slice()方法。我们首先来介绍下splice()方法,因为它应该算是最强大的数组方法了。

splice(a,b,c)接收三个参数,a代表执行操作的位置,b代表在操作位置执行删除操作的次数,c代表需要插入操作位置的值,可以是多个,返回值为删除的数组项。根据a,b,c三个参数传入的情况不同可以衍生出三种对数组的操作。

删除:

var nameArr = ["Tom","Lily","Sam","Bill"],
    item = nameArr.splice(1,2);
alert(nameArr); //Tom,Bill
alert(item); //Lily,Sam

省略参数c即为对数组的删除操作。但是这里要注意删除这个过程是怎么样进行的,首先找到数组中位置1即"Lily",当执行一次删除操作后原本位于位置2的"Sam"上前补位到位置1,之后执行第二次删除操作。理解这个过程后理解插入与替换方法变得更加容易。

插入

item = nameArr.splice(1,0,"Kobe","James");
alert(nameArr); //Tom,Kobe,James,Bill
console.log(item); //空数组

令参数b为0,即对位置1不执行删除操作,只插入"Kobe","James"两项。

替换:

item = nameArr.splice(2,2,"Fanfan");
alert(nameArr); //Tom,Kobe,Fanfan
alert(item); //James,Bill

先对位置2进行两次删除操作,移除并返回"James","Bill"两项,然后在位置2添加"Fanfan"。

当完全理解了splice()方法后,就可以把它当成一种操作。分成三种只是方便理解。

concat()方法,用于基于当前数组创建一个新数组。简单来说就是首先创建原数组的一个副本,然后将接收的参数添加到数组末尾,返回新数组。

var arr = [1,2,3],
    arr2 = arr.concat([4,5]),
    arr3 = arr.concat(6,7),
    arr4 = arr.concat(8,[9,10]);
alert(arr); //1,2,3
alert(arr2); //1,2,3,4,5
alert(arr3); //1,2,3,6,7
alert(arr4); //1,2,3,8,9,10

从上例可以看出,传入的参数不论是单独的值还是数组或者二者混合,都可以拼接成新数组。

slice()方法,基于当前数组中的若干项创建一个新的子数组。接收两个参数,第一个参数为起始位置,第二个参数为结束位置。返回从起始位置到结束位置前一项组成的数组,如果不指定结束位则到数组末尾。

var arr = [1,2,3,4,5,6,7,8,9,10],
    arr2 = arr.slice(3),
    arr3 = arr.slice(3,8);
alert(arr); //1,2,3,4,5,6,7,8,9,10
alert(arr2); //4,5,6,7,8,9,10
alert(arr3); //4,5,6,7,8

感谢您的浏览,希望能对您有所帮助。

JavaScript——引用类型之数组

标签:

原文地址:http://www.cnblogs.com/ghost-xyx/p/4440362.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!