用js来实现那些数据结构01(数组篇01-数组的增删)
在开始正式的内容之前,不得不说说js中的数据类型和数据结构,以及一些比较容易让人混淆的概念。那么为什么要从数组说起?数组在js中是最常见的内存数据结构,数组数据结构在js中拥有很多的方法,很多初学者记不清数组的大多数用法,只知道push,pop,shift等最基本的几个。所以,本系列(数组篇)会尽可能的让大家对数组有一个透彻的了解。也方便后面其他数据结构的学习和使用。
可能很多web前端开发者都会有一个疑问,那就是,数组和对象究竟是数据类型?还是数据结构?那么我们就带着这样的疑问,开始下面的学习,希望看完这篇文章之后,你模糊的概念会变得清晰一些。
首先,在js中,数据类型分为两种,基本类型(原始类型)和复杂类型,其中,基本类型是:String(字符串),Number(数值),Boolean(布尔值),还有undefined和null。复杂类型是Objecct(对象)。
说到这里大家可能会有些疑问,只有这六种类型?那数组(Array),正则(RegExp),日期(Date)算是什么?其实他们都是Object(对象)的一个分支,换句话说它们都属于Object类型,这也正是js与众不同的地方——万物皆对象。而后面要聊的包括队列,栈,链表,集合,树,图等数据结构在js中的展现方式,也都是通过对象和原型来实现的。本文无意去详细的描述数据类型和数据结构的种类以及在js中的体现形式。所以点到为止。
故事已经开始,请大家系好安全带,跟着我驰骋在在这篇广阔的土地上——数组。
先解释一下什么是数组吧,所谓数组,是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个“名”称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按无序的形式组织起来的一种形式。这些无序排列的同类数据元素的集合称为数组。简单来说数组就是用于储存多个相同类型数据的集合。(当然,js中的数组也可以存储不同类型数据,但是!不建议这样做!)
一、数组的创建和初始化
相信很多小伙伴都知道创建一个数组十分容易:
var arr = [];
这样我们就创建了一个数组,我们还可以用new关键字来创建并初始化一个数组:
//创建一个空数组 var newArr = new Array(); //创建一个指定长度的数组 var newLenArr = new Array(4); //创建一个具有指定参数的数组 var numArr = new Array(1,2,3,4);
当然,通过new关键字创建并初始化数组的方式并不推荐,这里只是给大家介绍一下。其实我们通过上面第一种方式来创建数组的本质就是通过new来实例化一个Array对象。OK,这里不多说它的实现原理,还是回到数组本身来吧。
那么我们如何读取数组中的数据呢?很简单,我就一句话带过了,也就是通过中括号([ ])arr[2],来传递数值的位置,获取到对应位置的值,也可以通过这种方式来重新赋值。
二、数组的增删
接下来说说如何使用js数组自带的方法来实现数组头尾的增删:push(数组尾部插入元素),unshift(数组头部插入元素),pop(数组尾部删除元素)和shift(数组头部删除元素)
1、push方法
如果我不想使用push方法,有没有什么方式可以在数组的尾部插入一个元素呢?其实很简单,我们只需要把值赋给数组中最后一个空位上的元素就可以了。
var nums = [0,1,2,3,4]; nums[nums.length] = 5;
我们通过length属性,获取该数组的长度是5,但是我们数组对应的下标是从0开始的,通过这样的方式,也就给数组的尾部插入了一个新的元素。当然,其实我们可以更方便的使用push来给数组的尾部插入一个元素:
var nums = [0,1,2,3,4]; nums.push(5);
也可以得到同样的结果。当然,push也可以传入多个参数,依次的从尾部插入数组:
var nums = [0,1,2,3,4]; nums.push(5,6,6); //[0,1,2,3,4,5,6,6]
2、unshift方法
那么同样的,如何在不使用原生方法的前提下给数组的头部添加一个元素呢?
var nums = [0,1,2,3,4,5,6]; for(var i = nums.length;i >= 0;i--){ nums[i] = nums[i - 1]; } //[undefined, 0, 1, 2, 3, 4, 5, 6] nums[0] = -1; //[-1, 0, 1, 2, 3, 4, 5, 6]
实际上,我们通过循环遍历,把nums数组中的每一位所对应的下标增加一个,也就是向后移动一位,那么这就导致了头部的位置空出(它的位置是存在的),但是此时我们并没有给空出的位置所对应的下标赋值,所以它的长度增加了值确实undefined,赋值之后,才会得到我们想要的结果。
下面我们还是用unshift方法来给数组的头部插入新值:
var nums = [0,1,2,3,4,5]; nums.unshift(-1); //[-1, 0, 1, 2, 3, 4, 5] nums.unshift(-2,-3); //[-2, -3, -1, 0, 1, 2, 3, 4, 5]
那么要注意一点,在使用unshift传入多个参数的时候,他会把第一个参数放在数组的头部(以此类推),也就是说unshift方法会把所有的参数依照顺序插入数组,并不是我们想当然的那样从第一个参数依次添加进数组。
3、pop方法
如果我想要删除数组尾部的元素,我们可以使用pop方法,其实我们还是可以用js来模拟一下pop:
var nums = [0,1,2,3,4,5]; nums.length = nums.length - 1; //[0, 1, 2, 3, 4]
我们可以通过手动让数组的长度减少一位,就可以实现删除数组尾部的元素,当然也可以减少两位三位等。
实际上,在日常开发中通常都会使用pop方法来删除数组尾部的元素(pop()方法没有参数,只是删除数组尾部的元素。):
var nums = [0,1,2,3,4,5]; nums.pop() // [0, 1, 2, 3, 4]
4、shift方法
那么接下来我们看看如何从数组的首位删除元素:
var nums = [0,1,2,3,4,5]; for(var i = 0; i < nums.length; i++) { nums[i] = nums[i + 1] } // [1, 2, 3, 4, 5, undefined]
可以看到,我们最后一位是undefined,也就是说在最后一次的循环里,i + 1引用了一个数组里还未初始化的位置(开辟了空间但是未赋值),所以,这样的方式只是依次覆盖了上一位的值,并没有真正的删除元素。如果想要删除首位的元素,这就需要用到shift方法了。
var nums = [0,1,2,3,4,5]; nums.shift(); // [1, 2, 3, 4, 5]
5、splice方法
最后,我们看看如何使用splice()方法,在数组的任意位置添加和删除元素:
var nums = [0,1,2,3,4,5,6,7]; nums.splice(2); //[0, 1] //如果只加一个参数,说明删除从下标2开始的所有的后面的元素
var nums = [0,1,2,3,4,5,6,7]; nums.splice(2,1); //[0, 1, 3, 4, 5, 6, 7] //如果加入两个参数,则为删除从下标2开始的后面的几个元素。
var nums = [0,1,2,3,4,5,6,7]; nums.splice(2,1,"a","b","c"); //[0, 1, "a", "b", "c", 3, 4, 5, 6, 7] //三个或多个参数,意味着删除从下标2(第一个参数)开始的后面的1个(第二个参数)元素,并在下标2的后面加入从第三个参数开始的后面的所有参数,把第二个参数设置为0就可以不删除元素从而实现从任意位置添加元素
再多说一点,我们还可以使用delete操作符来删除数组中的元素,但是实际上,delete只是删除了对应下标上所存储的值,并没有同时把存储值得空间也删除掉,会导致对应位置上的值为undefined:
var nums = [0,1,2,3,4,5,6,7]; delete nums[2]; //[0, 1, undefined, 3, 4, 5, 6, 7]
splice()方法是修改了原数组的。
6、slice()
slice()方法,会返回参数选定的范围的数组。该方法有两个参数,start(必选)和end(可选)。这两个值可以为负数,如果为负数则默认从尾部的第一个参数算起,也就是说-1就是数组的最后一个元素,-2就是数组的倒数第二个元素,以此类推。如果不传end,则默认从start开始直到数组最后一个元素都会被截取。
var nums = [0,1,2,3,4,5,6,6,7,"a",9,10,{name:"zaking"},["b","c"]]; var a = nums.slice(1,5); console.log(a);//[1, 2, 3, 4] var b = nums.slice(-1,5); console.log(b);//[] var c = nums.slice(-1,-5); console.log(c);//[] var d = nums.slice(-5,-1); console.log(d);// ["a", 9, 10, {…}] var f = nums.slice(5,1); console.log(f);//[] var x = nums.slice(5); console.log(x);// [5, 6, 6, 7, "a", 9, 10, {…}, Array(2)] var y = nums.slice(-5); console.log(y)//["a", 9, 10, {…}, Array(2)]
希望大家仔细看一下这个例子,当然,我还是一句话说明一下吧。
其实主旨就是,你所传的参数无论正负,参数所限定的范围必须是包含数组元素的。
那么数组的一些基本用法就先介绍到这里,后面应该还有两篇左右的长度来介绍数组。花费如此的篇幅,实在是数组真的极为重要,还请大家不要着急。当真正的学会了数组之后,再去看栈,队列这种数据结构,其实就很简单了。
最后,由于本人水平有限,能力与大神仍相差甚远,若有错误或不明之处,还望大家不吝赐教指正。非常感谢!