背景:
又是居家办公的一天,闲来没事刷刷朋友圈。就看到了一条引人入目的标题:JavaScript的数组默认排序规则。 哟,瞬间就让摸鱼状态离体而去,学习状态立马入魂。让我来刨析这道菜。
干货:
在JavaScript的sort排序中,它可以接受一个非必传的函数。
函数:sort()
- 作用:对数组排序
- 参数:非必传的回调函数function(a,b){},决定排序规则。
- 降序:从小排到大:arr.sort(function(a,b){return a-b});
- 升序:从大排到小:arr.sort(function(a,b){return b-a});
现在我们从传函数和不传递函数两者情况来分析。
1. 不传递函数
let arr = [23,112233];
arr.sort();
//打印结果
[ 112233, 23 ]
这是为什么呢?因为在sort函数中,当我们直接调用没有传函数参数时,它的底层代码是根据数组元素内容的第一个下标值对应的 ASCII码 来排序。 像上面的例子。第一个元素内容是23,对应的第一个下标值是2,对应的 ASCII码是50;第二个元素内容是112233,对应的第一个下标值是1,对应的 ASCII码是49。因此该数组排序结果是:[ 112233,23 ]。 再来个例子
let arr = ['ast','A'];
arr.sort();
//打印结果
[ 'A', 'ast' ]
如上,a字符的ASCII码是97,A字符的ASCII码是65,所以结果如上。
2. 传递函数
sort()函数其实跟es6的高阶函数filter、find等函数相似,都接受一个回调函数作为参数,只是sort的回调函数只接受两个参数,一个是当前值,一个是后面值。 如果 当前值-后面值>0,则升序,反之是降序。
下面看一下例子。
var arr = [22, 111, 3, 5, 6, 1];
//升序
arr.sort((a, b) => {
return a - b;
})
//打印结果为:
[ 1, 3, 5, 6, 22, 111 ]
//降序
arr.sort((a, b) => {
return b - a;
})
//打印结果为:
[ 111, 22, 6, 5, 3, 1 ]
在以上的基础上,我们就可以封装工具,来针对需要进行排序的业务功能。
下面我举了一个例子:
对于CSS的优先级处理时,我们知道 important > 内联 > id > class/伪类/属性 > 元素/为元素 > 通用 >继承样式。那么我们就可以通过sort来实现。
const rules = [
{
value: "类名",
weight: 300,
},
{
value: "内联",
weight: 500,
},
{
value: "id",
weight: 400,
},
{
value: "标签名",
weight: 200,
},
{
value: "通配符",
weight: 100,
},
];
const array = ["标签名", "通配符", "内联", "id", "类名"];
array.sort((a, b) => {
const first = rules.find((item) => item.value == a).weight;
const second = rules.find((item) => item.value === b).weight;
return second - first;
});
console.log(array);
//打印结果:
[ '内联', 'id', '类名', '标签名', '通配符' ]
以上就是一个demo。当然除了sort排序之外,还要冒泡排序、选择排序、插入排序、快速排序得到。这几种排序都不会很难。直接上代码+注释
扩展:
1. 冒泡排序
从下标0开始进行两辆交换,把最大的放到数组末端
var a = [1,4,3,5,6,2,11,7];
function maopao(a){
for(var i=a.length-1;i>0;i--){
for(var j=0;j<i;j++){
if(a[j]>a[j+1]){
[a[j],a[j+1]] = [a[j+1],a[j]]
}
}
}
return a
}
console.log(maopao(a));
2. 选择排序
从起始位置开始,获取比当前起始位置的值还小的值进行互换,循环进行
var a = [1,4,3,5,6,2,11,7];
function selectList(list){
//1.获取数组长度
var length =list.length; //7
//2.外层循环:从0位置开始取出数据,直到length-1位置
for(var i=0;i<length-1;i++){
//3.内层循环:从i+1位置开始,和后面的进行比较
var min =i
for(var j=min+1;j<length;j++){
//4.如果1位置的数据大于j位置的数据,那么记录最小的位置
if(list[min]>list[j]){
min=j
}
}
//5.把当前循环的起点下标和最小数的下标进行互换,即把最小值放到了第一个
[list[min],list[i]] = [list[i],list[min]]
}
return list
}
console.log(selectList(a));
3. 插入排序
- 外层循环:从第一个位置开始获取数据,向前面局部有序进行插入
- 内层循环:获取i位置的元素,和i-1的数据依次进行比较
- j位置的数据,放置temp的数 据即可
var a = [1,4,3,5,6,2,11,7,9];
//插入排序
function insertSort(list) {
var length = list.length
//外层循环:从第一个位置开始获取数据,向前面局部有序进行插入
for(var i=1;i<length;i++){
//内层循环:获取i位置的元素,和i-1的数据依次进行比较
var temp = list[i]
var j =i
while(list[j-1] > temp && j>0){
list[j] = list[j-1]
j--
}
//将j位置的数据,放置temp的数据即可
list[j] = temp
}
return list
}
console.log(insertSort(a))
4.快速排序
快速排序的核心思想是分而治之,先选出一个数据(比如65),将比其小的数据都放在它的左边,将比它大的数据都放在它的右边。这个数据称为枢纽 快速排序的枢纽:
- 第一种方案: 直接选择第一个元素作为枢纽。但是,当第一个元素就是最小值的情况下,效率不高;
- 第二种方案: 使用随机数。随机数本身十分消耗性能,不推荐;
- 优秀的解决方法: 取index为头、中、位的三个数据排序后的中位数;如下图所示,按下标值取出的三个数据为:92,31,0,经排序后变为:0,31,92,取其中的中位数31作为枢纽(当(length-1)/2不整除时可向下或向上取整)
//交换函数
let swap = function (arr, m, n) {
[arr[m], arr[n]] = [arr[n], arr[m]];
};
//枢纽函数
let median = function (arr) {
let left = 0;
let right = arr.length - 1;
let center = Math.floor((left + right) / 2);
if (arr[left] > arr[center]) {
swap(arr, left, center);
}
if (arr[center] > arr[right]) {
swap(arr, center, right);
}
if (arr[left] > arr[center]) {
swap(arr, left, center);
}
return center;
};
//快速排序
let QuickSort = function (arr) {
if (arr.length == 0) {
return [];
}
let center = median(arr);
let c = arr.splice(center, 1);
let l = [];
let r = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] < c) {
l.push(arr[i]);
} else {
r.push(arr[i]);
}
}
return QuickSort(l).concat(c, QuickSort(r));
};
let arr = [0, 13, 81, 43, 31, 27, 56, 92];
console.log(QuickSort(arr));
总结:
以上就是今天的内容,要是有优化的空间可以私聊我,下班去咯。