一篇文章带你掌握数组

867 阅读27分钟

1. 数组概述

1.1 定义:

数组(array)是按次序排列的一组值。每个值的位置都有编号(从0开始),整个数组用方括号表示。

注意:任何类型的数据,都可以放入数组,可以是(数字,字符,布尔值,对象,数组,函数);如果数组的元素还是数组,就形成了多维数组。

数组有两种定义方式:

  • 先定义,后赋值:代码所示

var arr=new Array();//创建一个空的数组,由于数组是对象,因此创建数组需要使用new运算符
//数组的索引值是从零开始的;
var arr=new Array(5);//创建一个长度为5的数组(有5个储存空间);
arr[0]=10;//arr[索引值]数组中对应的储存空间;
arr[1]=20;//索引值就是数组中每个值的位置对应的编号;从零开始;
arr[2]=30;
arr[3]=40;
arr[4]=50;
console.log(arr);

  • 定义的时候赋值,代码所示:

var arr=[10,20,30,40,50];
//arr.length=5

1.2 数组的本质 

本质上,数组属于一种特殊的对象。typeof运算符会返回数组的类型是object

typeof ([1, 2, 3]);  //object 

上面代码表明,typeof运算符认为数组的类型就是对象,因此创建数组需要使用new运算符。

1.3 数组的特点

  1. 数组是值的有序集合
  2. 由于弱类型的原因,JavaScript中数组十分灵活、强大,不像是Java等强类型高级语言数组只能存放同一类型或其子类型元素,JavaScript在同一个数组中可以存放多种类型的元素。 
  3. js数组长度也是可以动态调整的,可以随着数据增加或减少自动对数组长度做更改。 

1.4 数组的基本要素

  1. 标识符:就是数组的名称,用于区分不同的数组 ;
  2. 数组元素:即向数组中存放的数据;
  3. 元素下标(索引值):对数组元素进行编号,从0开始,数组中的每个元素都可以通过下标来访问 ;
  4. 数组长度,length属性表示数组的长度,即数组中元素的个数;

1.5 for...in 循环和数组的遍历 

for...in循环不仅可以遍历对象,也可以遍历数组,毕竟数组只是一种特殊对象。

var a = [1, 2, 3];

for (var i in a) {
  console.log(a[i]);
}// 1 2 3

数组的遍历可以考虑使用for循环或while循环。

var a = [1, 2, 3];

// for循环
for(var i = 0; i < a.length; i++) {
  console.log(a[i]);
}

// while循环
var i = 0;
while (i < a.length) {
  console.log(a[i]);
  i++;
}

var l = a.length;
while (l--) {
  console.log(a[l]);
}

1.6 二维数组

二维数组:一维数组内容还是数组;代码所示;

<script>
		var arr=[[11,22,33],[44,55,66],[77,88,99]];
		// console.log(arr[0][1]);
		// 遍历二维数组
		for(var n=0;n<arr.length;n++){  //外层循环拿到二维数组中的一维数组;
			for(var j=0;j<arr[n].length;j++){
				console.log(arr[n][j]);  //遍历指定一维数组;
			}
		}
	</script>

2. 数组的基本处理函数

先来看一个需求:var arr=[11,22,33,44];在这个数组的第一个位置添加一个元素10;

var arr=[11,22,33,44];
for(n=arr.length;n>=0;n--){
		 //需要开辟一个新的空间出来,将原有的值向后移动一位,
                 //到第一个位置时,让值等于要插入的元素;
	if (n==0) {
		 arr[0]=10;
        }else{
		 arr[n]=arr[n-1];
	 }
}
console.log(arr);

显然,如果这么做会很麻烦,所以我们来学习一些函数;

2.1 Array 对象方法

方法描述
concat()连接两个或更多的数组,并返回结果。
join()把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。
pop()删除并返回数组的最后一个元素
push()向数组的末尾添加一个或更多元素,并返回新的长度。
reverse()颠倒数组中元素的顺序。
shift()删除并返回数组的第一个元素
slice()从某个已有的数组返回选定的元素
sort()对数组的元素进行排序
splice()删除元素,并向数组添加新元素。
toSource()返回该对象的源代码。
toString()把数组转换为字符串,并返回结果。
toLocaleString()把数组转换为本地数组,并返回结果。
unshift()向数组的开头添加一个或更多元素,并返回新的长度。
valueOf()返回数组对象的原始值

2.1.1 末尾添加 .push()  末尾删除 .pop()   开头添加 .unshift()  开头删除 .shift()

  • push()   在数组的末尾添加一个或多个元素(多个元素时,用逗号隔开);并且返回新数组的长度;               返回:就是执行完等于什么;

    var arr=[11,22,33,44,55];
    var x=arr.push(66,77);   
    console.log(arr);   
    console.log(x);

  • pop()     删除最后一个元素,返回被删除的元素;

    var arr=[11,22,33,44,55];
    var z=arr.pop();
    console.log(arr);
    console.log(z);

  • unshift()    在数组的开头添加一个或多个元素(多个元素时,用逗号隔开);并且返回新数组的长度;

    var arr=[11,22,33,44,55];  
    var y=arr.unshift(8,10);  
    console.log(arr);  
    console.log(y);

  • shift()    删除第一个元素,并且返回被删除的元素;
    var arr=[11,22,33,44,55];
    var x=arr.shift();
    console.log(arr);
    console.log(x); 

2.1.2 splice() 删除指定的元素,或在指定的位置添加元素

 (需求:想要在数组 var arr=[11,22,33,44,55]; 第二个位置添加新内容;

    splice()   有两个作用 

  • 第一个作用:如果括号中只有两个参数,是删除指定元素 ;返回被删除的元素                  其中,第一个参数:发生变化的位置;        第二个参数:向后删除几个元素。

    var arr=[11,22,33,44,55];
    var x=arr.splice(1,1);
    console.log(arr);//4) [11, 33, 44, 55]
    console.log(x);//[22]

  • 第二个作用:如果有三个参数,是添加(或插入)元素    前两个参数作用不变,第三个以及以后的参数,是要添加的元素;返回被删除的元素;

    var arr=[11,22,33,44,55];
    var x=arr.splice(1,1,99);
    console.log(arr);//[11, 99, 33, 44, 55]
    console.log(x);//[22]

2.1.3 concat()  数组合并    

 将两个或多个数组合并,然后返回出来,不会改变原始数组;

var arr1=[11,22,33];
var arr2=[44,55,66];
var arr3=[77,88,99];
var x=arr1.concat(arr2,arr3);
console.log(x);  

2.1.4 indexOf()和.lastIndexOf() 检测指定元素是否在数组

需求:检测指定元素是否在数组中

.indexOf()   检测指定元素是否在数组中,如果在,返回第一次出现位置(即元素所在的下标),如果不在,返回-1;

var arr1=[12,23,54,12,65];
var x=arr1.indexOf(12);
console.log(x);

lastIndexOf() 检测指定元素是否在数组中,如果在,返回最后一次出现位置(即元素所在的下标),如果不在,返回-1;

var arr1=[12,23,54,12,65];
var x=arr1.lastIndexOf(12);
console.log(x);
console.log(typeof(arr)); 

2.1.5 sort() 数组的排序

sort() 方法用于对数组的元素进行排序。语法:

arrayObject.sort(sortby)
参数描述
sortby可选。规定排序顺序。必须是函数。

返回值:对数组的引用。请注意,数组在原数组上进行排序,不生成副本。

说明:如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。

如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:

  • 若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
  • 若 a 等于 b,则返回 0。
  • 若 a 大于 b,则返回一个大于 0 的值。

var arr1=[12,23,54,12,65];
arr1.sort();
console.log(arr1); 

2.1.6 reverse() ,数组倒置(将数组中的内容 颠倒一下 ),返回倒置后的数组

var arr1=[12,23,54,12,65];
arr1.reverse();
console.log(arr1); 

2.1.7 join() 

.join()是通过指定的字符,将数组变成字符串,返回出来  

 join(参数)用参数链接数组中的元素,如果参数不写的话默认是逗号;

var arr1=[12,23,54,12,65];
var str=arr.join("*");
console.log(str);
console.log(typeof(str)); 

2.1.8 map() 

.map()方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。

array.map(function(elem, index, arr), thisValue)

map方法将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回。

var numbers = [1, 2, 3];

numbers.map(function (n) {
  return n + 1;
});
// [2, 3, 4]

numbers
// [1, 2, 3]

上面代码中,numbers数组的所有成员依次执行参数函数,运行结果组成一个新数组返回,原数组没有变化。

map方法接受一个函数作为参数。该函数调用时,map方法向它传入三个参数:当前成员、当前位置和数组本身。

[1, 2, 3].map(function(elem, index, arr) {
  return elem * index;
});
// [0, 2, 6]

上面代码中,map方法的回调函数有三个参数,elem为当前成员的值,index为当前成员的位置,arr为原数组([1, 2, 3])。

map方法还可以接受第二个参数,用来绑定回调函数内部的this变量(详见《this 变量》一章)。

var arr = ['a', 'b', 'c'];

[1, 2].map(function (e) {
  return this[e];
}, arr)
// ['b', 'c']

上面代码通过map方法的第二个参数,将回调函数内部的this对象,指向arr数组。

如果数组有空位,map方法的回调函数在这个位置不会执行,会跳过数组的空位。

var f = function (n) { return 'a' };

[1, undefined, 2].map(f) // ["a", "a", "a"]
[1, null, 2].map(f) // ["a", "a", "a"]
[1, , 2].map(f) // ["a", , "a"]
[1, '', 2].map(f) //["a", "a", "a"]

上面代码中,map方法不会跳过undefinednull,但是会跳过空位。

实例2:求数组中每个元素的平方根

var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
/* roots的值为[1, 2, 3], numbers的值仍为[1, 4, 9] */

实例3:将下边两个字符串拼接成["A1", "A2", "A", "B1", "B2", "B", "C1", "C2", "C", "D1", "D2", "D"]

var arr1 = ['A', 'B', 'C', 'D'];        
var arr2 = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2'];        
var x = arr1.map( elem => elem + 3)        
var y = x.concat(arr2).sort().map( elem => elem.replace(/3/g , "") )
//(12) ["A1", "A2", "A", "B1", "B2", "B", "C1", "C2", "C", "D1", "D2", "D"]

2.1.9 slice() 方法

slice方法用于提取目标数组的一部分,返回一个新数组,原数组不变。

arr.slice(start, end);

它的第一个参数为起始位置(从0开始),第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员。

var a = ['a', 'b', 'c'];

a.slice(0) // ["a", "b", "c"]
a.slice(1) // ["b", "c"]
a.slice(1, 2) // ["b"]
a.slice(2, 6) // ["c"]
a.slice() // ["a", "b", "c"]

上面代码中,最后一个例子slice没有参数,实际上等于返回一个原数组的拷贝。

如果slice方法的参数是负数,则表示倒数计算的位置

var a = ['a', 'b', 'c'];
a.slice(-2) // ["b", "c"]
a.slice(-2, -1) // ["b"]

上面代码中,-2表示倒数计算的第二个位置,-1表示倒数计算的第一个位置。

如果第一个参数大于等于数组长度,或者第二个参数小于第一个参数,则返回空数组。

var a = ['a', 'b', 'c'];
a.slice(4) // []
a.slice(2, 1) // []

slice方法的一个重要应用,是将类似数组的对象转为真正的数组。

Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })
// ['a', 'b']

Array.prototype.slice.call(document.querySelectorAll("div"));
Array.prototype.slice.call(arguments);

上面代码的参数都不是数组,但是通过call方法,在它们上面调用slice方法,就可以把它们转为真正的数组。


var arr = new Array(3);
arr[0] = "George";
arr[1] = "John";
arr[2] = "Thomas";
document.write(arr + "<br />");
document.write(arr.slice(1) + "<br />");
document.write(arr);
//George,John,Thomas
//John,Thomas
//George,John,Thomas

实例:数组拆分的函数

function sliceArray(array, size) {        
    var result = [];        
    for (var x = 0; x < Math.ceil(array.length / size); x++) {            
        var start = x * size;            
        var end = start + size;            
        result.push(array.slice(start, end));        
    }       
    return result;    
}

let pages = [];        
array.forEach((item,index) => {            
    let x = parseInt(index/8);            
    if (!pages[x]) {                
        pages[x] = [];            
    }            
    pages[x].push(item);        
})        
console.log(pages)

2.1.10 forEach() 方法

forEach方法与map方法很相似,也是对数组的所有成员依次执行参数函数。但是,forEach方法不返回值,只用来操作数据。这就是说,如果数组遍历的目的是为了得到返回值,那么使用map方法,否则使用forEach方法。

forEach的用法与map方法一致,参数是一个函数,该函数同样接受三个参数:当前值、当前位置、整个数组。

function log(element, index, array) {
  console.log('[' + index + '] = ' + element);
}

[2, 5, 9].forEach(log);
// [0] = 2
// [1] = 5
// [2] = 9

上面代码中,forEach遍历数组不是为了得到返回值,而是为了在屏幕输出内容,所以不必使用map方法。

forEach方法也可以接受第二个参数,绑定参数函数的this变量。

var out = [];

[1, 2, 3].forEach(function(elem) {
  this.push(elem * elem);
}, out);

out // [1, 4, 9]

上面代码中,空数组outforEach方法的第二个参数,结果,回调函数内部的this关键字就指向out

注意,forEach方法无法中断执行,总是会将所有成员遍历完。如果希望符合某种条件时,就中断遍历,要使用for循环。

var arr = [1, 2, 3];

for (var i = 0; i < arr.length; i++) {
  if (arr[i] === 2) break;
  console.log(arr[i]);
}
// 1

上面代码中,执行到数组的第二个成员时,就会中断执行。forEach方法做不到这一点。

forEach方法也会跳过数组的空位。

var log = function (n) {
  console.log(n + 1);
};

[1, undefined, 2].forEach(log)
// 2
// NaN
// 3

[1, null, 2].forEach(log)
// 2
// 1
// 3

[1, , 2].forEach(log)
// 2
// 3

上面代码中,forEach方法不会跳过undefinednull,但会跳过空位。

2.1.11 filter() 方法

filter方法用于过滤数组成员,满足条件的成员组成一个新数组返回。

它的参数是一个函数,所有数组成员依次执行该函数,返回结果为true的成员组成一个新数组返回。该方法不会改变原数组。

[1, 2, 3, 4, 5].filter(function (elem) {
  return (elem > 3);
})
// [4, 5]

上面代码将大于3的数组成员,作为一个新数组返回。

var arr = [0, 1, 'a', false];

arr.filter(Boolean)
// [1, "a"]

上面代码中,filter方法返回数组arr里面所有布尔值为true的成员。

filter方法的参数函数可以接受三个参数:当前成员,当前位置和整个数组。

[1, 2, 3, 4, 5].filter(function (elem, index, arr) {
  return index % 2 === 0;
});
// [1, 3, 5]

上面代码返回偶数位置的成员组成的新数组。

filter方法还可以接受第二个参数,用来绑定参数函数内部的this变量。

var obj = { MAX: 3 };
var myFilter = function (item) {
  if (item > this.MAX) return true;
};

var arr = [2, 8, 3, 4, 1, 3, 2, 9];
arr.filter(myFilter, obj) // [8, 4, 9]

上面代码中,过滤器myFilter内部有this变量,它可以被filter方法的第二个参数obj绑定,返回大于3的成员。

2.1.12 reduce( ) 和 reduceRight()

定义: reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。 

语法: 

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

reduce方法和reduceRight方法依次处理数组的每个成员,最终累计为一个值。它们的差别是,reduce是从左到右处理(从第一个成员到最后一个成员),reduceRight则是从右到左(从最后一个成员到第一个成员),其他完全一样。

[1, 2, 3, 4, 5].reduce(function (a, b) {
  console.log(a, b);
  return a + b;
})
// 1 2
// 3 3
// 6 4
// 10 5
//最后结果:15

上面代码中,reduce方法求出数组所有成员的和。第一次执行,a是数组的第一个成员1b是数组的第二个成员2。第二次执行,a为上一轮的返回值3b为第三个成员3。第三次执行,a为上一轮的返回值6b为第四个成员4。第四次执行,a为上一轮返回值10b为第五个成员5。至此所有成员遍历完成,整个方法的返回值就是最后一轮的返回值15

reduce方法和reduceRight方法的第一个参数都是一个函数。该函数接受以下四个参数。

  1. 累积变量,默认为数组的第一个成员(必选)
  2. 当前变量,默认为数组的第二个成员(必选)
  3. 当前位置(从0开始)(可选)
  4. 原数组(可选)

reduce方法 第二个参数,(可选)

initialValue可选。传递给函数的初始值

这四个参数之中,只有前两个是必须的,后两个则是可选的。

如果要对累积变量指定初值,可以把它放在reduce方法和reduceRight方法的第二个参数。

[1, 2, 3, 4, 5].reduce(function (a, b) {
  return a + b;
}, 10);
// 25

上面代码指定参数a的初值为10,所以数组从10开始累加,最终结果为25。注意,这时b是从数组的第一个成员开始遍历。

上面的第二个参数相当于设定了默认值,处理空数组时尤其有用。

function add(prev, cur) {
  return prev + cur;
}

[].reduce(add)
// TypeError: Reduce of empty array with no initial value
[].reduce(add, 1)
// 1

上面代码中,由于空数组取不到初始值,reduce方法会报错。这时,加上第二个参数,就能保证总是会返回一个值。

下面是一个reduceRight方法的例子。

function subtract(prev, cur) {
  return prev - cur;
}

[3, 2, 1].reduce(subtract) // 0
[3, 2, 1].reduceRight(subtract) // -4

上面代码中,reduce方法相当于3减去2再减去1reduceRight方法相当于1减去2再减去3

由于这两个方法会遍历数组,所以实际上还可以用来做一些遍历相关的操作。比如,找出字符长度最长的数组成员。

function findLongest(entries) {
  return entries.reduce(function (longest, entry) {
    return entry.length > longest.length ? entry : longest;
  }, '');
}

findLongest(['aaa', 'bb', 'c']) // "aaa"

上面代码中,reduce的参数函数会将字符长度较长的那个数组成员,作为累积值。这导致遍历所有成员之后,累积值就是字符长度最长的那个成员。

2. 数组去重

方法一:

var arr=[11,22,33,44,55,22,22,33,54];//拿到数组中不重复的元素
var x=[];  //定义一个空数组
for(var n=0;n<arr.length;n++){
    if (x.indexOf(arr[n])==-1){
        x.push(arr[n]);//怎么判断新的数组中是否有arr[n]这个元素呢;
    }
}
console.log(x.sort());

方法二:

var arr=[11,22,33,44,55,22,33,54];
for(var n=0;n<arr.length;n++){
	for(var j=n+1;j<arr.length;j++){
		if (arr[n]==arr[j]) {
			arr.splice(arr.indexOf(arr[j]),1);
			j--;
		}
	}
}
console.log(arr)

方法三:

var arr=[11,22,33,44,55,22,33,54];
for(var n=0;n<arr.length;n++){
	if (arr.indexOf(arr[n])!=arr.lastIndexOf(arr[n])){
		//判断arr[n]出现的次数,如果次数不是一次,那么删除后边的元素
		arr.splice(arr.lastIndexOf(arr[n]),1);
		n--;//没有这个n--,相当于执行了8次,
	}
}
console.log(arr);

如果没有n--
  var arr=[11,22,33,33,33,44,55,22,22,33,54,33];
// [11,22,33,33,33,44,55,22,22,33,54,33]第1次执行 12 n=0
// [11,22,33,33,33,44,55,22,33,54,33]第2次执行 11 n=1
// [11,22,33,33,33,44,55,22,33,54]第3次执行 10 n=2
// [11,22,33,33,44,55,22,54]第4次执行 n=3
// [11,22,33,33,44,55,22,54]第5次执行 n=4
// [11,22,33,33,44,55,22,54]第6次执行 n=5
// [11,22,33,33,44,55,54]第7次执行 n=6
// [11,22,33,33,44,55,54]第8次执行 n=7

有了n--
  var arr=[11,22,33,33,33,44,55,22,22,33,54,33];
// (10)[11, 22, 33, 33, 33, 44, 55, 22, 22, 33, 54, 33] n=0时执行,执行完之后 n=0
// (11) [11, 22, 33, 33, 33, 44, 55, 22, 33, 54, 33] n=1时执行,执行完之后 n=0
// (10) [11, 22, 33, 33, 33, 44, 55, 33, 54, 33] n=1时执行,执行完之后 n=0
// (10) [11, 22, 33, 33, 33, 44, 55, 33, 54, 33] n=1时执行,执行完之后 n=1
// (9) [11, 22, 33, 33, 33, 44, 55, 33, 54] n=2时执行,执行完之后 n=1
// (8) [11, 22, 33, 33, 33, 44, 55, 54] n=2时执行,执行完之后 n=1
// (7) [11, 22, 33, 33, 44, 55, 54] n=2时执行,执行完之后 n=1
// (6) [11, 22, 33, 44, 55, 54] n=2时执行,执行完之后 n=1
// (6) [11, 22, 33, 44, 55, 54] n=2时执行,执行完之后 n=2
// (6) [11, 22, 33, 44, 55, 54] n=3时执行,执行完之后 n=3
// (6) [11, 22, 33, 44, 55, 54] n=4时执行,执行完之后 n=4
// (6) [11, 22, 33, 44, 55, 54] n=5时执行,执行完之后 n=5

3. 数组排序

3.1 sort排序法

(1)简单数组的简单排序

var arrSimple=new Array(1,8,7,6);
arrSimple.sort();
console.log(arrSimple.join()) ;复制代码

(2)简单数组的自定义排序

var arrSimple2=new Array(1,8,7,6);
arrSimple2.sort(function(a,b){    
    return a-b
});
console.log(arrSimple2.join())复制代码

解释:a,b表示数组中的任意两个元素,a-b输出从小到大排序,b-a输出从大到小排序。

(3)简单对象 List 自定义属性排序

var objectList = new Array();
function Persion(name,age){      
    this.name=name;      
    this.age=age;
}
objectList.push(new Persion('jack',20));
objectList.push(new Persion('tony',25));
objectList.push(new Persion('stone',26));
objectList.push(new Persion('mandy',23));
//按年龄从小到大排序
objectList.sort(function(a,b){      
    return a.age-b.age
});
for(var i=0;i<objectList.length;i++){      
    document.writeln('<br />age:'+objectList[i].age+' name:'+objectList[i].name);
}复制代码

(4)简单对象 List 对可编辑属性的排序

var objectList2 = new Array();        
function WorkMate(name,age){            
    this.name=name;            
    var _age=age;            
    this.age=function(){                
        if(!arguments){                    
            _age=arguments[0];
         }else{                   
            return _age;
         }                
    }                            
}        
objectList2.push(new WorkMate('jack',20));        
objectList2.push(new WorkMate('tony',25));        
objectList2.push(new WorkMate('stone',26));        
objectList2.push(new WorkMate('mandy',23));        
//按年龄从小到大排序        
objectList2.sort(function(a,b){            
    return a.age()-b.age();          
});        
for(var i=0;i<objectList2.length;i++){            
    document.writeln('<br />age:'+objectList2[i].age()+' name:'+objectList2[i].name);  
}复制代码

3.2 冒泡排序法

解析:1.比较相邻的两个元素,如果前一个比后一个大,则交换位置。

   2.第一轮的时候最后一个元素应该是最大的一个。

   3.按照步骤一的方法进行相邻两个元素的比较,这个时候由于最后一个元素已经是最大的了,所以最后一个元素不用比较)(所以减 i )。

var arr=[7,20,3,8,4,9,4,0,-4,1]        
function sort(elements){            
    for(var i=0;i<elements.length-1;i++){                
        for(var j=0;j<elements.length-i-1;j++){                    
            if(elements[j]>elements[j+1]){                        
                var swap=elements[j];                        
                elements[j]=elements[j+1];                        
                elements[j+1]=swap;                    
            }                
        }            
    }        
}         
console.log("before:"+arr)//before:[7,20,3,8,4,9,4,0,-4,1] 
sort(arr);        
console.log("after:"+arr) //after:-4,0,1,3,4,4,7,8,9,20复制代码

二维数组使用冒泡排序

方法1:

var arr=[["北京",80],["上海",50],["福州",10],["广州",50],["成都",70],["西安",100]];
var t;
for(var i=0;i<arr.length;i++){    
    for(var j=0;j<arr.length-1;j++){        
        if(arr[j][1]>arr[j+1][1]){            
            t=arr[j][1];            
            arr[j][1]=arr[j+1][1];            
            arr[j+1][1]=t;        
        }    
    }
}
console.log(arr);  
//["福州",10],["上海",50],["广州",50],["成都",70],["北京",80],["西安",100]复制代码

方法2:(选择排序法)

var arr=[["北京",80],["上海",50],["福州",10],["广州",50],["成都",70],["西安",100]];
for(var i=0;i<arr.length;i++){        
    for(var j=i+1;j<arr.length;j++){                
        if(arr[i][1]>arr[j][1]){                        
            var t=arr[j][1];                        
            arr[j][1]=arr[i][1];                        
            arr[i][1]=t;                
        }        
    }
}
console.log(arr);  复制代码

冒泡排序动图:


3.3  选择排序法

相对于冒泡排序还有一种类似的方法就是选择排序,顾名思义就是选择性排序,什么意思呢?
这么来理解,假设在三伏天有一趟室内游泳课,教练说了先在露天场地等着,从你们当中先选取最大个先进去,然后再从剩余的人中选择最大个进去,依次类推。那么小个的就在想了,教练你TMD的脑子是不是被驴踢了。但是如果是冒泡排序那更有意思了,所有的人先排好队再进去,这样还好一点最起码每个人的心理能平衡一点。简单理解选择排序就是从一个未知数据空间,选取数据之最放到一个新的空间。
废话不多说,看例子:

var array = [1,4,-8,-3,6,12,9,8];        
function selectSort(arr){            
    for(var i=0;i<arr.length;i++){                
    //设置当前范围最小值和索引                
    var min = arr[i];             
    var minIndex = i;                
    //在该范围选出最小值                
        for(var j=i+1;j<arr.length;j++){                    
            if(min>arr[j]){                       
                min = arr[j];                       
                minIndex = j;                    
            }                
        }                
    //将最小值插入,并将原来位置的最小值删除                
    arr.splice(i,0,min);                
    arr.splice(minIndex+1,1);            
    }        
}        
selectSort(array);        
document.write(array);复制代码

  • (1)在未排序序列中找到最小(大)元素
  • (2)并存放到排序序列的起始位置
  • (3)然后,再从剩余未排序元素中继续寻找最小(大)元素
  • (4)然后放到已排序序列的末尾。
  • (5)以此类推

选择排序动图


4. 练习题

4.1 求数组 var arr=[10,20,30,40,50];的总分和平均分;

<script>
		var arr=[10,20,30,40,50];
		var sum=0;
		var average=0;
		for(var n=0;n<arr.length;n++){
			sum=sum+arr[n];
			average=sum/arr.length;
		}
		console.log(sum);
		console.log(average);
	</script>

4.2 一个数组中求最大(小)值-并且找出其位置;

<script>            //最大值
		var arr=[11,22,33,44,88,66];
		var max=arr[0];	//假设max为数组中的第一个数,且是最大的
		var index=0;  //思想:假设index为数组中第一个数的位置编号(索引值)
		for(var n=1;n<arr.length;n++){
			if (arr[n]>max) {  //检测后边数组中有没有比他大的数
				max=arr[n];	//有的话,就让max重新赋值为比他大的数;
				index=n;	//index等于比他大的数的位置
			}
		}
		console.log(max);
		console.log(index);
	</script>

<script>
		var arr=[11,22,33,44,88,66];
		var min=arr[0];
		var index=0;
		for(n=1;n<arr.length;n++){
			if (arr[n]<min) {
				min=arr[n];
				index=n;
			}
		}
		console.log(min);
		console.log(index);
	</script>

4.3 对数组进行排序 (选择排序法 或者 冒泡排序法) 

 var arr=[21,23,18,96,15,56,85,52,12];

<script>
		//从大到小进行排序 拿出第一个数与后边的数进行比较,
                //选出最大的一个数,然后再拿第二个数与后边的数进行比较;
		//1.选择排序法
		var arr=[21,23,18,96,15,56,85,52,12];
		for(var n=0;n<arr.length;n++){		//依次拿到数组中的数
			for(var j=n+1;j<arr.length;j++){  //拿到后面的数
				if (arr[j]>arr[n]) {	//如果后边的数比前面的数大,就交换位置
					var t=arr[n];
					arr[n]=arr[j];
					arr[j]=t;
				}
			}
		}
		console.log(arr)
	</script>

4.4 级联列表 用JS实现下拉列表


<body>
	<select name="" id="bt1"></select>
	<select name="" id="bt2"></select>
	<script>
	//默认样式,  静态样式
		var arr=["河北","河南","山东","北京"];//定义一个省份数组
			//然后利用遍历数组,把数组放到对应的select中;
		var str="";
		for(var n=0;n<arr.length;n++){
			str=str+"<option>"+arr[n]+"</option>";
		}
		var bt1=document.getElementById("bt1");
		bt1.innerHTML=str;
		var city=[["秦皇岛","石家庄","唐山"],["许昌","郑州","洛阳"],["青岛","济南","淄博"],["西城","朝阳","海淀"]];
				//定义一个二维数组,放置省份对应的市区,
				//由于默认显示的是河北,所以第二个下拉列表中需要显示河北对应的市区;
				//所以要遍历city数组中第一个小数组;
		var str1="";
		for(var j=0;j<city[0].length;j++){
			str1=str1+"<option>"+city[0][j]+"</option>";
		}
		var bt2=document.getElementById("bt2");
		bt2.innerHTML=str1;
	//JS交互
		//需求:当第一个下拉列表发生变化时,第二个下拉列表随之发生变化;
		//onclick 点击事件   onchange 改变事件,当内容发生变化时,触发函数;
		//思路:1.找到当前改变后的位置;
		//		2.遍历对应的数组;
		//		3.拼接字符串,插入到bt2中;
		bt1.onchange=function(){
			// console.log("触发了");
			var index=bt1.selectedIndex;//bt1中,当前选中option位置的索引值;
			//问题:为什么要拿到对应的位置?   因为需要找到其对应的小数组的位置;
			console.log("index="+index);
			var str2="";
			for(n=0;n<city[index].length;n++){
				str2=str2+"<option>"+city[index][n]+"</option>";
			}
			bt2.innerHTML=str2;
		}
	</script>
</body>

4.5 级联列表-图片 

我们第五题的基础上,加入图片;当第一个下拉列表发生变化时,第二个下拉列表随之发生变化;对应的图片也发生变化。

<body>
	省份:<select name="" id="bt1"></select>
	市:<select name="" id="bt2"></select>
	<img src="" alt="" id="img">;
	<script>
	var arr=["河南","河北","山东","北京"];
	var str="";
	for(var n=0;n<arr.length;n++){
		str=str+"<option>"+arr[n]+"</option>";
	}
	var bt1=document.getElementById("bt1");
	bt1.innerHTML=str;
	var city=[["许昌","郑州","洛阳"],["秦皇岛","石家庄","邢台"],["青岛","济南","日照"],["西城","东城","海淀"]];
			//将图片的地址保存在数组里;保持一一对应关系
	var image=[["图片.jpg",".jpg","jpg"],["1","2","3"],["4","5","6"],["7","8","9"]];
	var str1="";
	for(var j=0;j<city[0].length;j++){
		str1=str1+"<option>"+city[0][j]+"</option>";
	}
	var bt2=document.getElementById("bt2");
	bt2.innerHTML=str1;
	//显示到默认的图片
	var img=document.getElementById("img");
	img.src=image[0][0];
	bt1.onchange=function(){
		var index=bt1.selectedIndex;
		console.log("indnx"+index);
		var str2="";
		for(i=0;i<city[index].length;i++){
			str2=str2+"<option>"+city[index][i]+"</option>";
		}
		bt2.innerHTML=str2;//改变到指定的图片
		//image[index]找到对应的图片数组
		////由于切换时永远显示第一张图片,那么直接将地址换成数组中的第一项;
		img.src=image[index][0];	
		bt2.onchange=function(){	
			var index=bt1.selectedIndex;//找到对应的大(一维)数组中的位置
			var index0=bt2.selectedIndex;//找到对应的小(二维)数组中的位置
			console.log("tp"+index0);
			img.src=image[index][index0];//根据数组及其位置,找到对应的图片;
		}
	}
	</script>
</body>

4.6 三级联动

<body>
	省:<select name="" id="bt1"></select>
	市:<select name="" id="bt2"></select>
	区:<select name="" id="bt3"></select>
	<img src="" alt="" id="img">;
	<script>
	var arr=["河北省","湖北省","河南省","山东省"];
	var city=[["秦皇岛市","石家庄市","保定市"],["武汉市","襄阳市","宜昌市"],
                 ["郑州市","许昌市","洛阳市"],["青岛市","济南市","日照市"]];
	var district=[[["海港区","抚宁区","开发区"],["长安区","桥西区","新华区"],
              ["竞秀区","莲池区","满城区"]],[["洪山区","汉口区","武昌区"],["襄城区","樊城区","襄州区"],
              ["西陵区","伍家岗区","点军区"]],[["中原区","二七区","金水区"],["禹州市","长葛市","郏县"],
              ["涧西区","西工区","洛龙区"]],[["市南区","市北区","黄岛区"],["历下区","市中区","槐荫区"],
              ["日照区","东港区","岚山区"]]];
	var image=[[["","",""],["", "",""],["","",""]],[["","",""],["","",""],["","",""]],
                     [["","",""],["","",""],["","",""]],[["","",""],["","",""],["","",""]]];
	var str="";
	for(n=0;n<arr.length;n++){
		str+="<option>"+arr[n]+"</option>";
	}
	var bt1=document.getElementById("bt1");
	bt1.innerHTML=str;
	var str1="";
	for(j=0;j<arr[0].length;j++){
		str1+="<option>"+city[0][j]+"</option>";
	}
	var bt2=document.getElementById("bt2");
	bt2.innerHTML=str1;
	var str3="";
	for(q=0;q<district[0][0].length;q++){
		str3+="<option>"+district[0][0][q]+"</option>";
	}
	var bt3=document.getElementById("bt3");
	bt3.innerHTML=str3;
	var img=document.getElementById("img");
	img.src=image[0][0][0];
//添加JS动态交互
	bt1.onchange=function(){
		var index=bt1.selectedIndex;//获取到bt1变化后的索引值;
		var str2="";
		for(i=0;i<city[index].length;i++){
			str2+="<option>"+city[index][i]+"</option>";
		}
		var bt2=document.getElementById("bt2");
		bt2.innerHTML=str2;
		str4="";
		for(e=0;e<district[index][0].length;e++){
			str4+="<option>"+district[index][0][e]+"</option>";
		}
		var bt3=document.getElementById("bt3");
		bt3.innerHTML=str4;
		img.src=image[index][0][0];
		bt2.onchange=function(){
			var index=bt1.selectedIndex;
			var index1=bt2.selectedIndex;//获取bt2变化后的索引值;
			console.log("p"+index1);
			var str5="";
			for(t=0;t<district[index][index1].length;t++){
				str5+="<option>"+district[index][index1][t]+"</option>";
			}
			bt3.innerHTML=str5;
			bt3.onchange=function(){
				var index=bt1.selectedIndex;
				var index1=bt2.selectedIndex;
				var index2=bt3.selectedIndex;
				console.log("x"+index2);
				img.src=image[index][index1][index2];
			}
		}
	}
	</script>
</body>