js 数组

数组对于一个编程语言而言可谓举足轻重,当然 JavaScript 也对其相当重视,下面我就将自己接触到的数组有关的属性和方法记录下来。此文章会不断完善,以供自己或他人查看。

简单介绍

有两种方式声明一个数组,如下所示

var arrayOne = new Array();
var arrayTwo = [];

按理说,以上两种方式声明的数组功能都是相同的,但是不建议使用第一种方式,准确的说,为了可读性以及代码的执行速度,我们选择第二种方式。

虽然第一种方式不建议使用,但为了给其面子还是来介绍一下它的使用方法。Array 有三个构造方法。

  1. 默认的无参构造方法

    var array = new Array();

    这种方式声明的数组默认数组长度为 0 。

  2. 带有数组元素的构造方法

    var array = new Array(1, 2, 3, 4);
  3. 指定数组长度的构造方法

    var array = new Array(5);

    数组的长度需要设定在 0 - 2^32 -1 之间的一个整数, 如果不是, 将会抛出 RangeError 异常。在事先不知道数组长度的情况下还是不要盲目使用这个方法。举个例子来说,当前我们指定数组的长度为 5,如果我们放进数组 10 个元素,数组的长度会自动增加到 10 。而如果我们只放进数组 1 个元素,那么其它的 4 个位置不就虚位以待了吗? 这在无形中也就浪费了我们的内存资源。

也许你已经看到了,上面介绍 2,3 两种 Array 构造方法存在冲突,如果我们指定如下代码,浏览器将会如何解释我们的代码呢?

var array = new Array(1);

其实以上代码会被默认解释为一个长度为 1 的空数组,如果你真的想将传进去的一个值作为数组中的元素,那么你只能将这个值当做字符串传进去了。

var array = new Array("1");

当然,我相信大部分人也不会用 new Array() 去声明一个数组,那么自然也不会有这样的问题存在了。

JavaScript 中, 数组被当做是一个对象,我们可以用以下代码去检测。

console.log(typeof(array));  // return object

既然如此,那么问题来了。 对于一个已知变量,我们怎么判断它是不是数组呢?显然我们不可以利用 typeof 了。有三种方法可以鉴别,下面来一一介绍。

  1. ECMAScript5 中有一个新方法 Array.isArray(),这个方法可以帮主我们鉴别变量是否为数组,如果是数组,返回 true, 否则返回 false。 但是这种方法存在一个问题,那就是老的浏览器并不支持 ECMAScript5

  2. 为了解决上一个方法中出现的问题,我们可以自己定义一个 isArray() 方法。

     function isArray(x) {
         return x.constructor
                 .toString()
                 .indexOf("Array") > -1;
     }
  3. 第三种方法需要借助 instanceof 关键词,这个方法可以确定一个对象是否由某一个构造函数所创建。

     array instanceof Array

在使用数组的时候需要尤其注意,因为数组是通过下标来操作元素的,比如 a[0],a[1] ...。但是有些时候由于错误的操作,极可能引发不可预知的问题,就像下面这样。

    var person = [];
    person["name"] = "hwaphon";
    person["age"] = 20;

可见,我们声明 person 为一个数组,却以操作对象的方式操作它,这个时候 JavaScript 会自动将其重定位为一个对象,这也就意味着数组当中的方法可能就失效了。比如说,这个时候调用 person.length 会返回 0 。但是值得注意的是,由于在重定位之前 person 是利用数组的构造函数产生的,所以这个时候如果你利用 Array.isArray() 去检测 person 会发现仍然返回 true

方法

说到数组,那么我们的本心就是利用数组来存储一组数据,那么也就面临了问题,我们该如何存取数据呢?

首先,用如下代码声明一个数组。

var array = [];

可以利用如下代码一直往数组的末尾添加一个元素。

array[array.length] = element;

至于如何获取数组中的值,可以直接指定数组的下标,比如说 a[0](如果这个元素尚没有指定值,将会返回 undefined)。

存取元素都解决了,还需要面对的一个问题是如何删除元素,或许我们可以通过下面这段代码删除最后一个元素(至于其它位置的元素,只需改变 i 的值即可)

    for (var i = 0; i < array.length; i++) {
        array[i] = array[i + 1];
    }

恩,看上去是这么回事,而且最后一个元素会被赋值为 undefined,非常完美。可是当调用 array.length 的时候发现数组的长度并没有改变,因为这样我们只是将值给删除了而已。没关系,还有办法,我们在重新声明一个数组,将当前数组非 undefined 的值复制进去就是了。哎,好像又需要写一个函数专门去做这件事了。体贴的 JavaScript 设计者自然也想到了这一点,我们可以使用其内置的方法去解决删除的问题,比如 pop(), shift(), splice()。下面来探讨一下这些方法的使用。

我们可以使用 push(), unshift() 方法在数组中插入元素,二者的区别在于 push() 方法会将元素插在数组的末尾,unshift() 方法将元素插在数组的开头。

    array.unshift(0);
    array.push(5);

使用 pop(), shift() 方法在数组中删除元素,二者的区别在于 pop() 删除数组的末尾元素,shift() 方法删除数组的起始元素。

    array.pop();
    array.shift();

可见,我们可以使用 push() 和 shift() 模仿队列的工作方式。

还有一个比较强大的方法,那就是 splice() 方法,我们可以利用它删除任何位置的任何长度元素,也可以替换掉数组中的一部分元素。

    array.splice(1,2);

以上代码的意思是,从数组下标 1 开始,连续删除两个元素。

    array.splice(1,0,5,6,7,8,9);

以上代码的意思是从数组下标 1 开始,删除 0 个元素,并且将 5,6,7,8,9 五个元素插入到数组当中去,而且是插入在下标 1 的后面。

  • 数组复制
    使用 slice(start, end) 方法,可以完成对一个数组的复制,当然可以选择性复制。

      var fullCopy = array.slice();
      var partCopy = array.slice(1,3);

    上面的第一种方法,是将 array 这个数组中的所有元素复制下来。 第二种方法指定了起始和终止下标,所以复制的是 array 中数组下标 1-3 的元素。

  • 数组合并

      var arrayOne = [0, 1, 2];
      var number = 3;
      var arrayTwo = [4, 5, 6];
    
      var resultArray = arrayOne.concat(number, arrayTwo);

    concat() 中的参数可指定多个,不过要注意先后顺序。

  • 迭代器函数
    JavaScript 内置了很多迭代器函数,下面来一一介绍。

    every(callback, thisArg) 方法会迭代数组中的每一个元素,直到有一个元素返回了 false。这个方法有两个参数,第一个参数是回调函数,而且该回调函数中还包含了三个参数,分别是 currentValue, index, arrayObj。第二个参数 thisArg 是可选的,用于指定回调函数中的 this 指针指向何处,如果不指定,则 this 指针为 undefined。这个方法有什么用呢?我们可以用于判断一组数据中的所有元素是否满足同一条件。比如说,我们用下面这个数组保存了 一部分人的年龄信息。

      var personAge = [18,25,102,-6];

    我们可以用 every() 函数判断所有的值是否都为正数,因为一个人的年龄不可能为负数吧。

      personAge.every(function(currentValue, index){
          if (currentValue < 0) {
              console.log("Index : " + index + ", value : " + currentValue);
              return false;
          }
          return true;
      });

    every() 方法对应的还有一个方法叫做 some() ,这二者的用法是一样的。这二者的差别在于,every() 方法用于检测一个数组中的元素是否全都满足同一条件,一旦有一个元素不满足条件,方法就会执行结束。而 some() 方法用于检测一个数组中是否有一个元素满足指定条件,如果有一个元素满足,也即回调函数返回了 true, 那么some() 方法就会结束执行。举个例子,高中的时候每次考完试,总有老师会问,有没有同学考到 90 分啊,当然老师的目的并不是想准确的知道班上有多少人考到 90 分,他只是想知道是否有人突破这一分数线,所以他想得到的答案为 是或否。我们可以用 some() 来模拟这一场景。

      var studentGrade = [55,66,77,88,99];
    
      studentGrade.some(function(currentValue, index) {
          if (currentValue >= 90) {
              console.log("I got " + currentValue + " points!");
              return true;
          }
          return false;
      })

    一般情况下,我们会利用 for 循环打印整个数组的值,但是为了方便我们也可以使用 forEach() 方法。这个方法的使用和上述介绍的 some(), every() 相同。比如下面利用 forEach() 遍历整个数组。

      var numbers = [55,66,77,88,99];
    
      numbers.forEach(function(currentVaule, index) {
          console.log("Index : " + index + ", value : " + currentVaule);
      });

    下面介绍两种能够返回新数组的迭代器方法。filter(callback, thisArg) 可以根据条件返回一个新的数组。

      var numbers = [55,66,77,88,99];
    
      var evenNumbers = numbers.filter(function(currentValue, index) {
          if (currentValue % 2 == 0) {
              return true;
          }
          return false;
      });
    
      for (var i = 0; i < evenNumbers.length; i++) {
          console.log(evenNumbers[i]);
      }

    上面打印的结果为 66,88。 也就是说,filter() 方法会将满足条件的值返回给新的数组。如果你想求一个数组中所有元素的和,那么 reduce(callback, thisArg) 方法能够帮到你,不过值得注意的是,这个方法的 callback 方法相比于上述介绍的有些差距,它的callback 形如 function(previousValue, currentValue, index, arrayObj)。下面利用这个函数来求一个数组的和。

      var numbers = [55,66,77,88,99];
    
      var result = numbers.reduce(function(previousValue, currentValue, index) {
          return previousValue + currentValue;
      });
    
      console.log(result);
  • 排序

    可以利用 reverse() 方法将一个数组中的元素逆序排列。值得注意的是这里的逆序排列只是将数组中的元素按照初始时的反过来的排放而已,并没有涉及到排序问题。

      var numbers = [1, 2, 3, 6, 5, 4, 11, 12, 13, 16, 15];
    
      numbers.reverse();
      for (var i = 0; i < numbers.length; i++) {
          console.log(numbers[i]);
      }

    这段代码的返回结果为 15,16,13,12,11,4,5,6,3,2,1

    上面没有涉及到排序,当然我们可以利用 sort() 方法对数组进行排序。

      var numbers = [1, 2, 3, 6, 5, 4, 11, 12, 13, 16, 15];
    
      numbers.sort();
      for (var i = 0; i < numbers.length; i++) {
          console.log(numbers[i]);
      }

    这段代码的返回结果为 1,11,12,13,15,16,2,3,4,5,6。 确定这是排序结果?天了噜,这简直是在逗我。为什么会这样呢? 因为 sort() 函数是将数组中的元素当做字符串来排序的,字符串又是根据字符在 ASCII 码来进行排序的。所以,我们只能自己去定义排序规则。

      var numbers = [1, 2, 3, 6, 5, 4, 11, 12, 13, 16, 15];
    
      numbers.sort(function(first, second){
          return first - second;
      });
    
      for (var i = 0; i < numbers.length; i++) {
          console.log(numbers[i]);
      }

    你可以根据自己的需要,为 sort() 指定用于比较的函数,此函数有三种类型的返回值,即 正数,0, 负数。

  • 输出为字符串

    为了满足某种需要,我们可能会将一个数组作为一个字符串返回,最简单的办法是借助于 toString()

      var numbers = [66,77,88,99];
    
      var numberString = numbers.toString();
      console.log(numberString);

    执行结果为 66,77,88,99。 可见,toString() 方法默认将两个数组元素用逗号隔开,当然我们还可以使用 join() 改变这一默认表现。

      var numbers = [66,77,88,99];
    
      var numberString = numbers.join("->");
      console.log(numberString);

    这时候的输出结果为 66->77->88->99



文/高华峰(简书作者)
原文链接:http://www.jianshu.com/p/d00857f2cd68
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值