zoukankan      html  css  js  c++  java
  • JavaScript——引用类型之数组

    前言

    之前本菜打算在写完基本类型后写引用类型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(compare);
    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】underscore
    【JavaScript】jQuery
    【JavaScript】浏览器
    【JavaScript】对象
    【JavaScript】函数
    【JavaScript】快速入门
    【python】异步IO
    【python】web开发
    【python】TCP/IP编程
    【python】常用第三方模块
  • 原文地址:https://www.cnblogs.com/ghost-xyx/p/4440362.html
Copyright © 2011-2022 走看看