JS_数组基础知识整理

数组

  • 什么是数组?

  • 字面理解就是 数字的组合

  • 其实不太准确,准确的来说数组是一个 存储数据的集合,也就是我们把一些数据放在一个盒子里面,按照顺序排好。

    [1, 2, 3, 'hello', true, false]
    
  • 这个东西就是一个数组,存储着一些数据的集合

  • 基本数据类型中变量只能存储 一个数据单元,数组中可以存储多个数据单元 。

  • 数组是一种特殊的对象

数据类型分类

  • number / string / boolean / undefined / null / object / function / array / …

  • 数组也是数据类型中的一种

  • 我们简单的把所有数据类型分为两个大类 基本数据类型复杂数据类型

  • 基本数据类型: number / string / boolean / undefined / null

  • 复杂数据类型: object / function / array / …

创建一个数组

  • 数组就是一个 []
  • [] 里面存储着各种各样的数据,按照顺序依次排好

字面量创建一个数组

  • 直接使用 [] 的方式创建一个数组

  • [] 中定义数组的数据单元,多个数据单元之间使用逗号间隔,数组的数据单元可以是任意JavaScript支持的数据类型。

    // 创建一个空数组
    var arr1 = []
    
    // 创建一个有内容的数组
    var arr2 = [1, 2, 3]
    var arr3 = ['北京' , '上海' , '广州' , '重庆' , '天津'];
    

内置构造函数创建数组

  • 使用 js 的内置构造函数 Array 创建一个数组----不推荐

    // 创建一个空数组
    var arr1 = new Array()
    
    // 创建一个长度为 10 的数组
    var arr2 = new Array(10)
    
    // 创建一个有内容的数组
    var arr3 = new Array(1, 2, 3)
    

数组的 length

  • length: 长度的意思

  • length 就是表示数组的长度,数组里面有多少个成员,length 就是多少

    // 创建一个数组
    var arr = [1, 2, 3]
    
    console.log(arr.length) // 3
    

数组的索引

  • 索引,也叫做下标,是指一个数据在数组里面排在第几个的位置。数组通过索引下标来操作数组的数据单元

  • 注意: 在所有的语言里面,索引都是从 0 开始的

  • js 里面也一样,数组的索引从 0 开始

    // 创建一个数组
    var arr = ['hello', 'world']
    
  • 上面这个数组中,第 0 个 数据就是字符串 hello第 1 个 数据就是字符串 world

  • 想获取数组中的第几个就使用 数组[索引] 来获取

    var arr = ['hello', 'world']
    
    console.log(arr[0]) // hello
    console.log(arr[1]) // world
    
  • 错误的索引下标,也能定义数组单元,但是数组的length 不会改变

    var arr = [1,2,3,4,5];
    arr[5.8] = '北京' ;
    arr[true] = '上海' ;
    console.log( arr[5.8] );	//=>北京
    console.log( arr );		//=> (5) [1, 2, 3, 4, 5, 5.8: '北京', true: '上海']
     console.log(arr.length);	//=> 5
    
  • 数组的基本操作

    /*
    1、新增 
      	对不存在的索引下标进行赋值操作。
     	本质核心:新增数组一个单元并且定义索引下标,同时赋值存储的数据。
    2、修改 
    	对已经存在的索引下标进行赋值操作。
    	本质核心:对数组已经存在的单元进行重复赋值,后赋值的数据会覆盖之前存储的数据,执行效果就			是数组的修改操作。
    3、设定数组单元长度
        数组.length---可以获取数组单元长度数据
    	数组.length = 数值;---可以设定数组单元长度
    */
    
     // 定义一个数组
    var arr = ['北京' , '上海' , '广州' , '重庆' , '天津'];
    
    // 调用
    // 通过索引下标调用指定索引下标中存储的数据数值
    console.log( arr[0] );		//=> 北京
    var res1 = arr[1] ;		
    console.log( res1 ); 		//=> 上海
    
    // 新增
    // 给数组新增一个数据单元,赋值定义索引下标是5同时存储数据数值 武汉
    arr[5] = '武汉' ;
    console.log(arr);			//=> (6) ['北京', '上海', '广州', '重庆', '天津', '武汉']
    // 实际项目中,索引下标必须是连续的索引下标,不能生成空数据单元
    // 空数据单元调用结果是undefined
    arr[50] = '大连' ;
    console.log( arr[20] );		//=> undefined
    console.log(arr.length);	//=> 51
    // 最后一个单元索引下标是 arr.length -1 
    // 新增单元的索引下标必须是连续的,新增的一个单元的索引下标也就是arr.length -1 + 1,即arr.length
    arr[ arr.length ] = '深圳';
    arr[ arr.length ] = 100;
    arr[ arr.length ] = 200;
    arr[ arr.length ] = 300;
    console.log(arr);	  //=> (55) ['北京', '上海', '广州', '重庆', '天津', '武汉', 							空属性 × 44,'大连', '深圳', 100, 200, 300]
    
    // 修改
    // 对已经存在的索引下标进行赋值操作
    arr[5] = true ; 	
    console.log( arr );	//=> (55) ['北京', '上海', '广州', '重庆', '天津', true, 空属性 × 44, 							    '大连', '深圳', 100, 200, 300]
    // 设定数组单元长度数据
    arr.length = 1;
    console.log( arr );	//=> ['北京']
    

数据类型之间存储的区别(重点)

  • 既然我们区分了基本数据类型和复杂数据类型
  • 那么他们之间就一定会存在一些区别
  • 他们最大的区别就是在存储上的区别
  • 我们的存储空间分成两种
  • 栈: 主要存储基本数据类型的内容
  • 堆: 主要存储复杂数据类型的内容

基本数据类型在内存中的存储情况

  • var num = 100,在内存中的存储情况
  • 直接在 栈空间 内有存储一个数据

复杂数据类型在内存中的存储情况

  • 下面这个 对象 的存储

    var obj = {
      name: 'Jack',
      age: 18,
      gender: '男'
    }
    
  • 复杂数据类型的存储

    1. 在堆里面开辟一个存储空间
    2. 把数据存储到存储空间内
    3. 把存储空间的地址赋值给栈里面的变量
  • 这就是数据类型之间存储的区别

数据类型之间的比较

  • 基本数据类型是 之间的比较

    var num = 1
    var str = '1'
    
    console.log(num == str) // true
    
  • 复杂数据类型是 地址 之间的比较

    var obj = { name: 'Jack' }
    var obj2 = { name: 'Jack' }
    
    console.log(obj == obj2) // false
    
    • 因为我们创建了两个对象,那么就会在 堆空间 里面开辟两个存储空间存储数据(两个地址)
    • 虽然存储的内容是一样的,但是也是两个存储空间,两个地址
    • 复杂数据类型之间就是地址的比较,所以 objobj2 两个变量的地址不一样
    • 所以我们得到的就是 false

数组的常用方法

  • 数组是一个复杂数据类型,我们在操作它的时候就不能再想基本数据类型一样操作了

  • 比如我们想改变一个数组

    // 创建一个数组
    var arr = [1, 2, 3]
    
    // 我们想把数组变成只有 1 和 2
    arr = [1, 2]
    
    • 这样肯定是不合理,因为这样不是在改变之前的数组
    • 相当于心弄了一个数组给到 arr 这个变量了
    • 相当于把 arr 里面存储的地址给换了,也就是把存储空间换掉了,而不是在之前的空间里面修改
    • 所以我们就需要借助一些方法,在不改变存储空间的情况下,把存储空间里面的数据改变了

数组的查询—indexOf、lastIndexOf

  • 查询执行的是全等比较( === )
  • 数组.indexOf(要查询的内容)
    如果有匹配的数据,返回值是第一个匹配数据所在单元的索引下标
    如果没有匹配的数据,返回值是 -1
  • 数组.lastIndexOf(要查询的内容)
    如果有匹配的数据,返回值是最后一个匹配数据所在单元的索引下标
    如果没有匹配的数据,返回值是 -1
  • 判断数组中有没有某一个数值
    如果结果是 -1 ,证明没有
    如果是其他数值,都证明有
// 定义数组
var arr = [1,2,3,1,2,3,4,1,2,3,4,5,1,2,3,4,5,6];

// 查询

// 返回第一个 3 所在单元的索引下标 
var res1 = arr.indexOf( 3 );
console.log( res1 );				//=> 2

// 没有匹配的数据 返回值是 -1
var res2 = arr.indexOf( '3' );
console.log( res2 );				//=> -1

// 返回最后一个 3 所在单元的索引下标 
var res3 = arr.lastIndexOf( 3 );
console.log( res3 );				//=> 14

// 没有匹配的数据 返回值是 -1
var res4 = arr.lastIndexOf( '3' );
console.log( res4 );				//=> -1

数组的新增—unshift、push

  • unshift 是在数组的最前面添加一个元素,首位新增

  • push 末位新增

  • 可以一次新增一个或者多个单元,多个单元使用逗号间隔。

  • 执行结果返回值是 新增单元之后,新数组的长度。也就是length属性值

    var arr = [100,200,300,400,500] ;
    
    // 首位新增
    // 函数的执行结果返回值是新增单元之后,新数组的length
    var res1 = arr.unshift('北京','上海','广州');
    console.log( res1 );	//=> 8
    console.log( arr );	//=> (8) ['北京', '上海', '广州', 100, 200, 300, 400, 500]
    
    // 末位新增
    var res2 = arr.push('aaa' , 'bbb' , 'ccc');
    console.log( res2 );    //=> 11
    console.log( arr );
    //=> (11) ['北京', '上海', '广州', 100, 200, 300, 400, 500, 'aaa', 'bbb', 'ccc']
    

数组的首位删除与末位删除—shift、pop

  • shift 是删除数组最前面的一个元素
  • pop 是用来删除数组末尾的一个元素
  • 删除一次只能删除一个单元,执行结果返回值是删除的数据
var arr = [100,200,300,400,500] ;

// 首位删除
var res3 = arr.shift();
console.log(res3);	//=> 100
console.log( arr );	//=>(4) [200, 300, 400, 500]

// 末位删除
var res4 = arr.pop();
console.log(res4);	//=> 500
console.log( arr );	//=> (3) [200, 300, 400]

数组的截取—slice

  • 数组.slice(参数1 , 参数2)
    参数1: 截取起始位置的索引下标
    参数2: 截取结束位置的索引下标

  • 截取内容不包括结束位置,包前不包后。

  • 注意: slice方法不会改变原始数组,执行结果返回值是截取的内容

    var arr = ['北京'  , '上海' , '广州' , '重庆' , '天津' , '武汉' , '深圳'] ;
    var res = arr.slice( 1 , 3 );
    console.log( arr );
    //=> (7) ['北京', '上海', '广州', '重庆', '天津', '武汉', '深圳']
    console.log( res );		//=> (2) ['上海', '广州']
    
    var res1 = arr.slice( 1 , 1 );
    console.log( res1 );	//=> []
    
    //=> 下标是1的单元开始,截取到最后
    var res2 = arr.slice( 1 );
    console.log( res2 );
    //=>(6) ['上海', '广州', '重庆', '天津', '武汉', '深圳']
    
    //负数
    //截取倒数第三个(包含)到倒数第一个(不包含)的两个元素
    //注意:倒数的时候,数数是从1开始数的。
    var res3 = arr.slice(-3, -1);
    console.log(res3);	//=> (2) ['天津', '武汉']
    
    //截取最后三个元素
    var res4 = arr.slice(-3);
    console.log(res4);	//=> (3) ['天津', '武汉', '深圳']
    

数组的删除—splice

  • splice 是删除数组中的某些内容,按照数组的索引来删除

  • 语法: splice(从哪一个索引位置开始,删除多少个,替换的新元素) (第三个参数可不写,也可以替换一个或者多个内容,多个内容使用逗号间隔)

    // 定义数组
    var arr = [100,200,300,400,500,600,700,800,900];
    
    // 从索引下标是2的 第三个单元开始,删除4个单元
    arr.splice( 2 , 4 );
    console.log( arr );	//=> (5) [100, 200, 700, 800, 900]
    // 从索引下是2的 第三个单元开始,删除1个单元,在删除的索引2的位置调换写入新的数据 'aaa'
    arr.splice( 2 , 1 , 'aaa' );  
    //=> (9) [100, 200, 'aaa', 400, 500, 600, 700, 800, 900]
    
    // 替换写入多个单元
    arr.splice( 2 , 1 , 'aaa' , 'bbb' , 'ccc' , 'ddd');
    console.log( arr );
    //=> (12) [100, 200, 'aaa', 'bbb', 'ccc', 'ddd', 400, 500, 600, 700, 800, 900]
    
    //也可以截取多个单元,但是写入一个数据
    arr.splice(1, 2, '我是新内容')
    console.log(arr)
    //=> (8) [100, '我是新内容', 400, 500, 600, 700, 800, 900]
    

数组的反转—reverse

  • reverse 是用来反转数组使用的
var arr = [1, 2, 3]
// 使用 reverse 方法来反转数组
arr.reverse()
console.log(arr)  //=> (3) [3, 2, 1]

数组的排序— sort

  • sort 是用来给数组排序的

  • 数组.sort(),默认

     按照首字符的大小排序    小 --- 大
    
  • 数组.sort( function(a,b){ return a-b } );

    ​ 按照数值的大小排序 小 — 大

  • 数组.sort( function(a,b){ return b-a } );

    ​ 按照数值的大小排序 大 — 小

    // 只有一位数,那么前两种方法一样
    var arr = [2, 3, 1];
    arr.sort();
    arr.sort(function(a,b){return a-b;});
    console.log(arr);	//=> (3) [1, 2, 3]
      
    // 多位数
    var arr = [43124,7654,6354,8765,34,432,1876,5,342,435298,5432,8764];
    
    // 首字符的大小顺序    小 --- 大
    arr.sort();	 
    console.log(arr);
    //=> (12) [1876, 34, 342, 43124, 432, 435298, 5, 5432, 6354, 7654, 8764, 8765]
    
    // 数值的大小顺序      小 --- 大
    arr.sort( function(a,b){return a-b} );
    console.log(arr);
    //=> (12) [5, 34, 342, 432, 1876, 5432, 6354, 7654, 8764, 8765, 43124, 435298]
    
    //  数值的大小顺序      大 --- 小
    arr.sort( function(a,b){return b-a} );
    console.log( arr );
    //=> (12) [435298, 43124, 8765, 8764, 7654, 6354, 5432, 1876, 432, 342, 34, 5]
    
    // 字符串,这里只能用arr.sort(); 另外两个无效
    var arr = ['a', 'b', 'd', 't', 'f', 'w', 'a', 'v', 'f', 'b', 'j', 'c', 'b', 'a'];
    arr.sort();	//=> ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'd', 'f', 'f', 'j', 't', 'v', 'w']
    
    //个人理解:先按照首字符从小到大排序,若首字符相同,则再按照第二个字符从小到大排序
    var arr = ['ba', 'b', 'vd', 'st', 'az', 'bw', 'ca', 'av', 'af', 'j', 'c', 'b', 'a'];
    arr.sort();	
    //=> ['a', 'af', 'av', 'az', 'b', 'b', 'ba', 'bw', 'c', 'ca', 'j', 'st', 'vd']
    

数组的拼接—concat

  • concat 是把多个数组进行拼接,将其他数组的数据拼接写入数组中。

  • 注意: concat 方法不会改变原始数组,执行结果返回值是拼接之后新数组,可以使用变量储存。

  • 一次可以拼接一个或者多个数组,多个数组之间使用逗号间隔。

 //拼接一个数组
  var arr = [1, 2, 3];
  var newArr1 = arr.concat([4, 5, 6])
  console.log(arr) 	 //=> (3) [1, 2, 3]
  console.log(newArr1) //=> (6) [1, 2, 3, 4, 5, 6]
  //也可以这么写
  var b= [4,5,6];
  var newArr2 = arr.concat(b);	//=> (6) [1, 2, 3, 4, 5, 6]
console.log(newArr2)
  
  //拼接多个数组
  var arr1 = [1,2,3,4,5];
  var arr2 = ['a' , 'b' , 'c' , 'd' , 'e'];
  var arr3 = [100,200,300,400,500];
  var newArr = arr1.concat( arr2 , arr3 );
  console.log( arr1 );	//=> (5) [1, 2, 3, 4, 5]
  console.log( newArr );	
  //=> (15) [1, 2, 3, 4, 5, 'a', 'b', 'c', 'd', 'e', 100, 200, 300, 400, 500]

数组和字符串的转化—join、split

  • 数组.join()

    1、把数组里面的每一项内容链接起来,转化为字符串。

    2、数组数据之间,默认以逗号为间隔转化为字符串。

    3、可以自己定义每一项之间链接的内容,

    ​ 若小括号中设定了字符,那么会以设定的字符为间隔;

    ​ 若小括号中设定 空字符串,那么内容之间就没有间隔。

    • 注意: join 方法不会改变原始数组,而是返回链接好的字符串
  • 字符串.split()

    1、将字符串字符分割为数组

    2、没有设定间隔符号,将字符串整体作为一个单元转化为数组

    3、设定间隔符号

    ​ 以设定的符号为间隔,将字符串分割为数组单元

    ​ 若是设定空字符串,那么会将每一个字符分割为一个数组单元

    // 定义的数组
    var arr = [1,2,3,4,5];
    
    // 数组 --- 字符串 1    默认以逗号为间隔
    var str1 = arr.join();
    console.log( str1 ); 	//=> 1,2,3,4,5
    
    // 数组 --- 字符串 2    以设定的字符为间隔
    var str2 = arr.join('/');
    console.log( str2 ); 	//=> 1/2/3/4/5
    console.log( arr ); 	//=> (5) [1, 2, 3, 4, 5]   原始的数组并没有改变
    
    // 数组 --- 字符串 2    以空字符串为间隔 没有间隔内容
    var str3 = arr.join('');
    console.log( str3 ); 	//=> 12345
            
    
    // 定义字符串
    // 字符串 --- 数组 1    将字符串作为一个整体,转化为一个数据单元
    var str = 'abcdefg' ;
    var arr1 = str.split();
    console.log( arr1 ); 	//=> ['abcdefg']
    
    // 字符串 --- 数组 2    按照设定的字符作为分割符号,将字符串转化为数组
    var str = 'a-b-c-d-e-f-g' ;
    var arr2 = str.split('-');
    console.log( arr2 ); 	//=> (7) ['a', 'b', 'c', 'd', 'e', 'f', 'g']
    var arr4 =str.split('');	//若是这里不写-'
    console.log( arr4 );	
    //=> (13) ['a', '-', 'b', '-', 'c', '-', 'd', '-', 'e', '-', 'f', '-', 'g']
    
    // 字符串 --- 数组 3    设定空字符串,每一个字符作为一个单元
    var str = 'abcdefg' ;
    var arr3 = str.split('');
    console.log( arr3 );	//=> (7) ['a', 'b', 'c', 'd', 'e', 'f', 'g']
    

数组的函数操作方法

数组的映射

数组.map(function(参数1,参数2,参数3){})
		 参数1: 	数组单元的数值数据,名称可以随便写,一般写成item或者value
  		 参数2: 	数组单元的索引下标 ,名称可以随便写,一般写成key或者index
   		 参数3: 	原始数组,名称可以随便写,一般写成array
			 也可以只写第一个参数

return   参数1的操作
			 将原始数组数据进行操作,生成新的映射的数组
var arr1 = [100,200,300,400,500];
// 使用变量储存数组映射的结果 也就是 映射的新的数组
var res1 = arr1.map(function(item , key , array){
// 返回的数据是 原始数组数据*2
	return item*2 ;
})
console.log( arr1 );	//=> (5) [100, 200, 300, 400, 500]
console.log( res1 );    //=> (5) [200, 400, 600, 800, 1000]  

数组的过滤

数组.filter(function(参数1,参数2,参数3){})
  			参数1: 	数组单元的数值数据   item    value
            参数2: 	数组单元的索引下标   key     index
            参数3: 	原始数组
   				也可以只写第一个参数     			 

return      参数1的比较判断
  			    将原始数组数据进行比较判断,将符合条件的数据生成新的数组
var arr2 = [100,200,300,400,500];
var res2 = arr2.filter(function(item){
// 将原始数组中大于300的数据生成一个新的数组
	return item > 300 ;
})
console.log( arr2 );	//=> (5) [100, 200, 300, 400, 500]
console.log( res2 );	//=> (2) [400, 500]          

数组的判断

1、数组.some(function(参数1,参数2,参数3){})
   			 参数1: 	数组单元的数值数据   item    value
   			 参数2: 	数组单元的索引下标   key     index
   			 参数3: 	原始数组

  return	 参数1的比较判断
 			 如果原始数组中**只要有一个**数据满足条件,返回值就是true

2、数组.every(function(参数1,参数2,参数3){})
      		参数1: 	数组单元的数值数据   item    value
      		参数2: 	数组单元的索引下标   key     index
      		参数3: 	原始数组

  return 	 参数1的比较判断
             如果原始数组中**所有数据**都满足条件,返回值才是true
var arr3 = [100,200,300,400,500];
// 只要有一个符合条件的数据 结果就是true
var res3 = arr3.some(function(item){
	return item > 300 ;
})

// 必须所有都符合条件 结果才是true 
var res4 = arr3.every(function(item){
	return item > 300 ;
})

console.log( res3 );	//=> true
console.log( res4 );	//=> false

数组的循环遍历

for循环

  • 使用循环方法操作数组中每一个数据单元

  • 数组[索引下标]只能操作一个数据单元

  • for循环可以通过控制i的数值,改变循环的执行

  • 可以使用 break 终止循环

var arr = [100,200,300,400,500,600,700];
// 操作程序是完全相同的,只是[]中的索引下标不同
// 索引下标是从0开始的整数,可以通过循环生成

// 通过 for 循环生成 0 - 最后一个单元的索引下标 
// 最后一个单元的索引下标是 数组.length-1 
for( var i = 0 ; i <= arr.length-1 ; i++ ){
	// i 就是 所有的索引下标
	console.log( i );
	//arr[i] 就是 所有的数据数值
	console.log( arr[i] );
}

/*
通过for循环遍历操作数组单元,语法形式是固定的形式
			for( var i = 0 ; i <= 数组.length-1 ; i++ )
也可以写成	 for( var i = 0 ; i < 数组.length ; i++ )
*/

for in和for of循环

  • for…in

    ​ for( var 变量 in 数组 ){
    ​ 循环体程序
    ​ }

    变量中自动存储每一个索引下标

  • for…of

    ​ for( var 变量 of 数组 ){
    ​ 循环体程序
    ​ }
    ​ 变量中自动存储每一个数据数值

    var arr = [100,200,300,400,500];
    for( var index in arr ){
    // index变量中自动以字符串形式数组单元的索引下标,数组[index]对应的就是是数据数值。
    	console.log( index );
    	console.log( arr[index] );
    }
    
    for( var value of arr ){
    // 只能通过break终止程序的执行
    	if( value === 300 ){
        	break;
        }
    	console.log( value );	//=> 会在控制台打印两次内容,分别是 100 he 200
    }      
    
    /*
    for...in
    for...of
    	不能通过修改参数的数值控制循环的执行步骤
    	只能从数组的第一个单元开始,一个一个的循环数组的所有单元
    	只能使用 break 终止循环
    */
    

forEach—数组特有的循环遍历语法

数组.forEach(function(参数1,参数2,参数3){})
             参数1: 	 	数据数值,也就是数组中的每一项
             参数2:  		索引下标
             参数3:  		原始数组
             
1、执行效率最低,不能控制循环的步骤,不能使用break终止
2、forEach()的时候传递的那个函数,会根据数组的长度执行,数组的长度是多少,这个函数就会执行多少回
var arr = ['北京' , '上海' , '广州' , '重庆' , '天津'];
arr.forEach(function(item,key,array){
// 不支持 break 语法
// if( key === 2 ){
//     break; 
// }
console.log( item,key,array );
// 输出结果
//=> 北京 0 (5) ['北京', '上海', '广州', '重庆', '天津']
//=> 上海 1 (5) ['北京', '上海', '广州', '重庆', '天津']
//=> 广州 2 (5) ['北京', '上海', '广州', '重庆', '天津']
//=> 重庆 3 (5) ['北京', '上海', '广州', '重庆', '天津']
//=> 天津 4 (5) ['北京', '上海', '广州', '重庆', '天津']
})

数组去重、数组坍塌

数组坍塌

	当数组执行删除单元操作时,被删除单元之后的单元会前移,进而顶替被删除单元,出现在被删除单元的位置上,造成数组长度减少的情况,这样的现象称为数组的坍塌。
	例如:[1,2,3,4,5] 删除数值3这个单元,数组会变成 [1,2,4,5],原始索引下标是2的位置上之前是数值3,现在是数值4
	
使用sort方法造成数组坍塌的备注:
	1,只要执行删除单元操作,数组一定会立即发生数组坍塌
	2,数组的坍塌一定会发生,不能阻止
	3,如果数组中存储重复数据,一定要考虑数组坍塌造成的影响
	4,通过控制循环变量 i 的数值,让触发数组坍塌的单元再次循环遍历
	5,哪儿触发删除,哪儿执行循环变量-- 操作    

数组去重

1、sort方法
	使用 数组.sort() 对数组数据进行排序,排序结果是相同的数据相邻在一起。之后循环遍历数组,当前单元和下一个单元存储的数据如果相同就删除后一个单元的数据。	
// 数组中存储了重复的数据,希望数组不要存储重复的数据,变成 [1,2,3,4,5,6,7]
var arr = [1,2,3,1,2,3,4,1,2,3,4,5,1,2,3,4,5,6,1,2,3,4,5,6,7];
// 对数组数值进行排序
arr.sort( function(a,b){return a-b} );
// 循环遍历数组
// 比较的是当前单元和下一个单元存储的数值,最后一个单元没有对应的下一个单元 进行比较判断,所以循环只要进行到倒数第二个单元就可以
for( var i = 0 ; i <= arr.length-1 - 1 ; i++ ){
// i 是索引下标,arr[i]是数据数值
// i+1 是 下一个单元的索引下标,arr[i+1]是下一个单元的数据数值
	if( arr[i] === arr[i+1] ){
    	// 删除 i+1 这个单元
    	arr.splice( i+1 , 1 );
		/*为了消除数组坍塌的影响,通过控制循环变量 i 的数值,让触发数组删除程序的单元,再次循环		    遍历,再次执行比较判断,也就是和坍塌过来的新的单元的数据再次比较判断。如果不写i--就会            出现数组坍塌而造成有单元没有执行操作。*/
		i--;
	 }
}
console.log( arr );		//=> (7) [1, 2, 3, 4, 5, 6, 7]
2、indexOf
使用indexOf方法完成数组去重
	创建一个新的空数组, 循环遍历原始数组, 需要使用indexOf判断新数组中有没有原始数组的数据, 
如果判断的结果是-1, 证明没有, 再执行添加操作; 使用方法---新数组.push()将原始数组中的数据写入新的数组。
// 原始数组
var arr = [1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7];
// 定义一个新的空数组
var newArr = [];
// 循环遍历原始数组, 将原始数组的数据写入新数组中
for (var i = 0; i < arr.length; i++) {
     // 在新数组newArr中判断有没有要写入的数据arr[i], 如果判断结果是-1, 证明没有, 再写入
	if (newArr.indexOf(arr[i]) === -1) {
		newArr.push(arr[i]);
	}
}
console.log(newArr);
3、双重for循环
核心思路:
1、外层循环:第一个至倒数第二。
	因为最后一个单元没有下一个单元进行比较判断, 所以外层循环至倒数第二个。
2、内层循环:外层的下一个至 最后一个。
3、外层循环索引下标对应的单元的数据和内层循环索引下标对应的单元的数据如果相同, 删除'内层'循环	索引下标对应的单元。
4、因为删除依据的是内层循环变量, 所以内层循环变量要执行 -- 操作, 再次循环这个位置, 防止数组坍塌的影响。
// 定义数组
var arr = ['a','b','c','a','b','c','d','a','b','c','d','e','a','b','c','d','e','f'];
// 双重for循环, 也就是循环两次
// 外层循环从第一个单元循环至倒数第二个单元
for( var i = 0 ; i <= arr.length-1-1 ; i++ ){
	// 内层循环从外层单元的下一个单元开始, 循环至最后一个单元
	for( var j = i+1 ; j <= arr.length-1 ; j++ ){
		// 如果外层单元 arr[i] 和内层单元 arr[j] 数值相同, 删除 j 对应的单元
		if( arr[i] === arr[j] ){
			// 从索引下标是 j 的位置, 开始删除1个单元
			arr.splice( j  , 1);
			// 为了消除数组坍塌的影响
             j--;                    
		}
	}
}
console.log( arr );

数组的排序

  • 排序,就是把一个乱序的数组,通过我们的处理,让他变成一个有序的数组
  • 今天我们讲解两种方式来排序一个数组 冒泡排序选择排序

冒泡排序

  • 先遍历数组,让挨着的两个进行比较,如果前一个比后一个大,那么就把两个换个位置

  • 数组遍历一遍以后,那么最后一个数字就是最大的那个了

  • 然后进行第二遍的遍历,还是按照之前的规则,第二大的数字就会跑到倒数第二的位置

  • 以此类推,最后就会按照顺序把数组排好了

    1. 我们先来准备一个乱序的数组

      var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8]
      
      • 接下来我们就会用代码让数组排序
    2. 先不着急循环,先来看数组里面内容换个位置

      // 假定我现在要让数组中的第 0 项和第 1 项换个位置
      // 需要借助第三个变量
      var tmp = arr[0]
      arr[0] = arr[1]
      arr[1] = tmp
      
    3. 第一次遍历数组,把最大的放到最后面去

      for (var i = 0; i < arr.length; i++) {
        // 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
        if (arr[i] > arr[i + 1]) {
          var tmp = arr[i]
          arr[i] = arr[i + 1]
          arr[i + 1] = tmp
        }
      }
      
      // 遍历完毕以后,数组就会变成 [3, 1, 5, 6, 4, 7, 2, 8, 9]
      
      • 第一次结束以后,数组中的最后一个,就会是最大的那个数字
      • 然后我们把上面的这段代码执行多次。数组有多少项就执行多少次
    4. 按照数组的长度来遍历多少次

      for (var j = 0; j < arr.length; j++) {
        for (var i = 0; i < arr.length; i++) {
          // 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
          if (arr[i] > arr[i + 1]) {
            var tmp = arr[i]
            arr[i] = arr[i + 1]
            arr[i + 1] = tmp
          }
        }
      }
      
      // 结束以后,数组就排序好了
      
    5. 给一些优化

      • 想象一个问题,假设数组长度是 9,第八次排完以后

      • 后面八个数字已经按照顺序排列好了,剩下的那个最小的一定是在最前面

      • 那么第九次就已经没有意义了,因为最小的已经在最前面了,不会再有任何换位置出现了

      • 那么我们第九次遍历就不需要了,所以我们可以减少一次

        for (var j = 0; j < arr.length - 1; j++) {
          for (var i = 0; i < arr.length; i++) {
            // 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
            if (arr[i] > arr[i + 1]) {
              var tmp = arr[i]
              arr[i] = arr[i + 1]
              arr[i + 1] = tmp
            }
          }
        }
        
      • 第二个问题,第一次的时候,已经把最大的数字放在最后面了

      • 那么第二次的时候,其实倒数第二个和最后一个就不用比了

      • 因为我们就是要把倒数第二大的放在倒数第二的位置,即使比较了,也不会换位置

      • 第三次就要倒数第三个数字就不用再和后两个比较了

      • 以此类推,那么其实每次遍历的时候,就遍历 当前次数 - 1

        for (var j = 0; j < arr.length - 1; j++) {
          for (var i = 0; i < arr.length - 1 - j; i++) {
            // 判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
            if (arr[i] > arr[i + 1]) {
              var tmp = arr[i]
              arr[i] = arr[i + 1]
              arr[i + 1] = tmp
            }
          }
        }
        
    6. 至此,一个冒泡排序就完成了

选择排序

  • 先假定数组中的第 0 个就是最小的数字的索引

  • 然后遍历数组,只要有一个数字比我小,那么就替换之前记录的索引

  • 知道数组遍历结束后,就能找到最小的那个索引,然后让最小的索引换到第 0 个的位置

  • 再来第二趟遍历,假定第 1 个是最小的数字的索引

  • 在遍历一次数组,找到比我小的那个数字的索引

  • 遍历结束后换个位置

  • 依次类推,也可以把数组排序好

    1. 准备一个数组

      var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8]
      
    2. 假定数组中的第 0 个是最小数字的索引

      var minIndex = 0
      
    3. 遍历数组,判断,只要数字比我小,那么就替换掉原先记录的索引

      var minIndex = 0
      for (var i = 0; i < arr.length; i++) {
        if (arr[i] < arr[minIndex]) {
          minIndex = i
        }
      }
      
      // 遍历结束后找到最小的索引
      // 让第 minIndex 个和第 0 个交换
      var tmp = arr[minIndex]
      arr[minIndex] = arr[0]
      arr[0] = tmp
      
    4. 按照数组的长度重复执行上面的代码

      for (var j = 0; j < arr.length; j++) {
        // 因为第一遍的时候假定第 0 个,第二遍的时候假定第 1 个
        // 所以我们要假定第 j 个就行
        var minIndex = j
        
        // 因为之前已经把最小的放在最前面了,后面的循环就不需要判断前面的了
        // 直接从 j + 1 开始
        for (var i = j + 1; i < arr.length; i++) {
          if (arr[i] < arr[minIndex]) {
            minIndex = i
          }
        }
      
        // 遍历结束后找到最小的索引
        // 第一堂的时候是和第 0 个交换,第二趟的时候是和第 1 个交换
        // 我们直接和第 j 个交换就行
        var tmp = arr[minIndex]
        arr[minIndex] = arr[j]
        arr[j] = tmp
      }
      
    5. 一些优化

      • 和之前一样,倒数第二次排序完毕以后,就已经排好了,最后一次没有必要了

        for (var j = 0; j < arr.length - 1; j++) {
          var minIndex = j
          
          for (var i = j + 1; i < arr.length; i++) {
            if (arr[i] < arr[minIndex]) {
              minIndex = i
            }
          }
        
          var tmp = arr[minIndex]
          arr[minIndex] = arr[j]
          arr[j] = tmp
        }
        
      • 在交换变量之前,可以判断一下,如果我们遍历后得到的索引和当前的索引一直

      • 那么就证明当前这个就是目前最小的,那么就没有必要交换

      • 做一我们要判断,最小作引和当前作引不一样的时候,才交换

        for (var j = 0; j < arr.length - 1; j++) {
          var minIndex = j
          
          for (var i = j + 1; i < arr.length; i++) {
            if (arr[i] < arr[minIndex]) {
              minIndex = i
            }
          }
        
          if (minIndex !== j) {
            var tmp = arr[minIndex]
            arr[minIndex] = arr[j]
            arr[j] = tmp   
          }
        }
        
    6. 至此,选择排序完成

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值