JavaScript 数组常用方法
ECMAScript3.0 是最标准的方法,之前学过的一系列东西,包括之后学的一系列东西都是基于es3.0,es3.0是最基础、最全面,最强大的一个通式版本,
ES5.0 是在 ES3.0 的基础上加了几个新方法而已,还并不是所有浏览器都好使,新版本浏览器支持ES5.0,老版本浏览器还没升级到ES5.0(比如老版本IE)。
ES6.0 是在 3.0、5.0 的基础上又提出的一些新方法,ES6.0是一个强大、飘逸的版本,现在学的是 es3.0 包含 es5.0 的(有些方法就不区分es3和es5了),
本次数组的方法都是 ES3.0 的方法,ES3.0 数组的方法是数组最重要的一些方法,然后把 es3.0 的方法分为两类,一种是可以改变原数组的一类,一种是不可以改变原数组的一类,按照这个分类学。
数组常用的方法
改变原数组 push, pop, shift, unshift, sort, reversem, splice
不改变原数组 concat, join —> split, toString, slice
一、可以改变数组的方法
这些方法都是可以改变原数组的,意思是在原数组的基础上去改变,添加或者剪切
方法名 | 作用 | 用法 |
---|---|---|
push() | 在数组最后一位添加 | var arr = [1,2,3]; arr.push(4); console.log(arr); // [1, 2, 3, 4] |
pop() | 从最后一位减去(删除) | |
unshift() | 在数组前面添加,和push方法相反 | |
shift() | 从数组前面减 | var arr = [1,2,3]; arr.shift(); console.log(arr); // [2, 3] |
reverse() | 反排数组 | |
splise() | 截取,在截取处插入 | |
sort() | 排序 |
1. push()
数组是引用值,是可以访问方法的,push方法是数组自己的不是什么包装类的
1 . push是往数组添加数据的方法,添加任何类型的数据都可以
2. 在哪添加数据?在数组的最后一位添加数据
var arr = []; console.log(arr.push(10)); // push是往数组里面放东西的,默认返回到是数组的长度"1",原来数组的长度是0 console.log(arr); // [10] console.log(arr.push(11)); // 再调用数组push一个11进去,默认返回数组长度是2 console.log(arr); // [10, 11] console.log(arr.push(9)); // 再push一个9进去,数组长度默认返回3 console.log(arr); // [10, 11, 9]
push方法还可以同时添加多个,怎么添加都行,这个方法特别的强大
var arr = [10, 11, 9]; arr.push(1,2,3,4,5,6,7); // 7 console.log(arr); // [10, 11, 9, 1, 2, 3, 4, 5, 6, 7]
我们自己写一个push方法,看看能不能覆盖系统的
1. push方法在Array原型上 Array.prototype.push
2. 调用push能打印出"哈哈",说明可以覆盖系统的
var arr = []; Array.prototype.push = function(){ return "哈哈"; } console.log(arr.push()); // 哈哈
在这个基础上重写一个 myPush 方法
1. 重写的push不能写形参,因为不知道要传多少位,所以只能用 arguments
2. push方法是把数据,放到数组的最后一位,怎么放到最后一位呢?
Array.prototype.myPush = function(){ for(var i = 0; arguments.length > i; i++){ // console.log(i, this.length); this[this.length] = arguments[i]; } return this.length; } var arr = ['1origin' ,'2origin']; console.log(arr.myPush(3,4,5,6)); // 6 console.log(arr); // ["1origin", "2origin", 3, 4, 5, 6]
思路:
比如数组 arr = [1,2] 里面已经有两位了,现在push一个数字3进去,3的位置应该在数组的最后一位
1. 数组从0位、1位开始算,数组的长度是的2
2. 长度2可以代表数组中有三位 0位,1位, 2位
3. push这个3应该在数组最后一位,而长度2表示数组的最后一位, arr[2] 中括号里的2是push进去3后数组的长度arr.length
4. 接下来再在给数组 arr = [1,2,3] 加一个4,arr[3] 中括号里面填的3,就是要往数组里面push的位置(最后一位)
所以,就是往数组第length位上填东西,因为length位还没出生呢,数组的最后一位永远是 length - 1
实现方式:
1. 把arguments遍历一下,把arguments里面的每一个东西都拿出来,
2. 数组不存在时原型链就存在了,原型链上的方法不知道今后是谁会去调用,不知道谁调用拿this代替, this[this.length] 谁调用它谁是this,
下次循环的时候this.length的长度自动就加1了,不用我们自己加加,数组就有这个特性
和系统自带的push一样,最后把数组的长度返回 return this.length
为什么写这个方法呢?
一方面启发下思路看系统怎么来实现的,另一方面以后要学会在原型链上编程。
什么叫在原型链上编程?
在原型链上写咱们通用的方法,
比如数组去重,去重方法数组没给咱们提供,咱们需要写到原型链上,让以后所有的数组都可以实现这个方法。
2. pop()
pop方法说删除不标准,先看效果
var arr = [1,2,3]; console.log(arr.pop()); // 返回3 console.log(arr); // 数组剩下[1, 2] console.log(arr.pop()); // 返回2 console.log(arr); // arr数组变成[1]
pop方法把数组的最后一位,不叫删除叫剪切出去,是把数组的最后一位剪切出去
变量num的值是3,变量num是数组最后一位剪切出来的那个数
var arr = [1,2,3]; var num = arr.pop(); console.log(num); // 3 console.log(arr); // [1, 2]
pop在执行的时候不用传参,传了也白传
var arr = [1,2,3]; arr.pop(2); // 想剪切两位 console.log(arr); // [1, 2] 数组只剪切最后一个,传的参数被忽略
总结
pop就是从最后一位去剪切,
push就是从最后一位去增加,
它俩是相反的
3. unshift()
shift 键盘上有这个键,unshift 方法别看加 un 了,但是 unshift 方法是添加东西的
比如给数组增加一个 0,unshift 是在数组的前面加东西,和 push 方向是相反的
var arr = [1,2,3]; arr.unshift(0); // 返回数组的长度 4 console.log(arr); // [0, 1, 2, 3]
unshift 是增加而且是在数组前面增加,那 shift 是从前面减
var arr = [1,2,3]; arr.shift(); // 1 console.log(arr); // [2, 3]
看看 unshift 能不能像 push 一样那么飘逸,加两个进去!
var arr = [1,2,3]; arr.unshift(-1, 0); // 返回数组长度 5 console.log(arr); // 数组变成 [-1, 0, 1, 2, 3]
unshift 方法能加两个进去
unshift 像 push 一样重写,怎么写?
先考虑插入的问题,看一个问题,数组能不能在它的 -1 负一位里面放东西?
var arr = [1,2,3]; arr[-1] = 0; console.log(arr); // [1, 2, 3, -1: 0]
没用,不能这么往前插东西
怎么办?
定义一个新的数组,然后把两个数组拼到一起就可以了,而且数组还有拼接方法叫 concat
不用 concat 方法,把参数当成一个新的数组,然后把原数组 push 到这个数组里就可以了,正好把原数组插入到新数组后面
Array.prototype.MyUnshift = function(newArr){ var valArr = []; // 内部新建数组 // 把argments挨个赋值给内部新数组valArr for(var i = 0; arguments.length > i; i++){ valArr[i] = arguments[i]; } // 把老数组(this) push给新valArr for(var i = 0; this.length > i; i++){ valArr.push(this[i]); } // valArr已经是"参数新数组"在前,老数组this在后, // 再把valArr重新覆盖老数组this,完成改变原数组。 for(var i = 0; valArr.length > i; i++){ this[i] = valArr[i]; } return this.length; } var arr = ["a",2,3]; console.log(arr.MyUnshift(5,6,"中文")); // 6 console.log(arr); // [5, 6, "中文", "a", 2, 3]
4. shift()
unshift 在数组前面增加,shift 方法从数组前面减
var arr = [1,2,3]; arr.shift(); // 1 console.log(arr); // [2, 3] arr.shift(); // 2 arr.shift(); // 3 arr.shift(); // undefined
5. reverse()
reverse 是逆反的意思,reverse() 方法逆转顺序后,它把原数组返回来,reverse 不是返回新数组,改变的是原数组
var arr = [1,2,3]; console.log(arr.reverse()); // [3, 2, 1] console.log(arr.reverse()); // [1, 2, 3] console.log(arr); // [1, 2, 3]
6. splice()
splice 方法是除 sort 以外相对复杂的一个方法了,而且它的应用非常多,splice 是切片的意思
splice( 从第几位开始,截取多少的长度,在切口处添加新的数据 )
方法难就难在传参上,里面传了好些个参数
先看截取的功能不看切的
从第一位开始截取,截取两位
1. arr.splice( 1, 2 ) 从第一位开始,应该包含第一位截取两位
2. [1, 1, 2, 2, 3, 3] 返回的是截取的部分 [1, 2]
var arr = [1, 1, 2, 2, 3, 3]; arr.splice(1,2); // 返回截取部分 [1, 2] console.log(arr); // 再打印原数组剩下[1, 2, 3, 3]
3. 换句话说截取也是一种剪切,不是完全删除,想关注返回结果 [1, 2] 拿变量接收,不想关注就不接收
在控制台上操作
截取后返回值 [1, 2]
截取后原数组变成 [1, 2, 3, 3]
再来,从第零为开始切,切三位,剩下的是什么?
var arr = [1, 1, 2, 2, 3, 3]; arr.splice(0, 3); // 返回[1, 1, 2] console.log(arr); // 剩下[2, 3, 3]
再来,
1. 从第一位开始切,切一个,
2. 然后,后面加参数了,后面的参数是无穷个的个数,后面的参数包含什么意思呢?
就是传多少个参数,都会把后面的参数全部放到切口处。传多少个都行,后面相当于在切口处的 push()
var arr = [1, 1, 2, 2, 3, 3]; arr.splice(1, 1, 0, 0, 0); // [1] console.log(arr); // [1, 0, 0, 0, 2, 2, 3, 3]
[ 1, 1, 2, 2, 3, 3 ]
[ 1, 1, 0, 0, 0, 2, 2, 3, 3 ]
那么问题来了,把 4 填到相应的位置上(3和5之间)怎么写?
var arr = [1, 2, 3, 5]; arr.splice(3, 0, 4); // [] console.log(arr); // [1, 2, 3, 4, 5]
[ 1, 2, 3 , , 5 ]
第零位 第一位 第二位 第三位 第四位
1. 如果光标定位在第三位不切,光标不往后移,
2. 在第三位定位,光标切0位就是不切,
3. 不切在这块填 4
再说明一下
1. 光标定位在第三位
2. 然后(这块很关键)然后光标就不切了,切0个,把刀疤留在这,不拿走东西,然后这块填东西
3. 不切的这块填 4
splice 方法用截取的次数概率比较小,用往里面填东西的概率比较大
有了splice方法之后,我们自己写的 MyUnshift 就好办了,在第 0 位开始截,截 0 个往里插东西就完事了,
splice 方法是非常强大的,会把截取完的的片段给反回来,还改变原数组。
splice 能从负数位开始截取吗?
从 -1 开始截取,截取一个(一般的数组方法都带负位)
var arr = [1, 2, 3, 4]; arr.splice(-1 ,1); // [4] 截取出来了 console.log(arr); // [1, 2, 3]
负一位 -1 的意思是倒数第一位,数组一般的方法里面都可以带负位的
数组在内部怎么实现负数的?
比如 spice 方法它第一个参数(pos)肯定是位置,pos 是怎么实现的,它是怎么把负数给归正的,也就是负一为什么是倒数第一位,为什么正一就是第二位?
var arr = [1, 2, 3, 4]; splice = function (pos){ pos += pos > 0 ? 0 : this.length; }
负一为什么是倒数第一位,为什么正一就是第二位?
如果传的是 -1,数组的 length 是 4,
公式是 -1 + 4 = 3 结果 3 是数组最后一位 4
如果传的是 -2,数组的 length 是 4,
公式 -2 + 4 = 2 结果 2 是数组正数二位 3
Ps:
编程尽量学完之后学的是编程,而不是学的是技术规律,技术规律没意思。
真正搞经济的人,真正在金融领域,高手之前都是编程的,我们这种程序化思维,特别有利于金融思维的启发。金融和编程是脱不了关系的,而且是相辅相成的。
所以把这个思维学会之后,想的是负数就是倒数第几位,可放到数字上实现的话就是另一种思维了,一定要学到这个过程,这是另一种思维法。
系统内部在实现 length 的时候,如果是负数的话,做这样一个兼容,如果是正数,正数就不用计算加了。
如果算负数,没法算负数,但是又想把负数的意义包含进来,怎么办法?加 lenght 就完事了。
如果越界,加一个判断(jQuery)
pos += pos > 0 ? 0 : this.length;
pos >= 0 || pos < length
算完的 pos,要大于等于 0 或者 pos 小 length,才有意义。
如果超界了,
数组的长度是5,放了一个 100 大于 length 不符合,
如果数组长度是5,放了一个 -100 它小于等于 0 了也不符合要求
7. sort()
给数组排序的,在原数组的基础上更改
1、sort 基本用法
arr 是一个无序的数组,无序数组想变成有序的怎么办?arr.sort() 会自小到大的顺序
var arr = [1,3,4,0,-1,9]; console.log(arr.sort()); // [-1, 0, 1, 3, 4, 9] console.log(arr); // [-1, 0, 1, 3, 4, 9]
上面是从小到大升序,想要从大到下降序 arr.sort().reverse() 这就降序了
var arr = [1,3,4,0,-1,9]; console.log(arr.sort().reverse());// [9, 4, 3, 1, 0, -1]
2、sort 的接口
换一个数组,用 sort() 方法升序排完是什么?结果这不是我们理想中的排序
var arr = [1,3,5,4,10]; console.log(arr.sort()); // [1, 10, 3, 4, 5]
sort() 把这些 [ 1, 3, 5, 4, 10 ] 全当成了字符按 ASCII 码排的,
sort() 可以按 ASCII 码排序字符,但是这个排序不是我们想要的,和我们要的相差甚远,我们想要的是数字排序
所以 sort() 方法留了一个编程接口,里面填一个匿名的 function 函数,这个 function 通过自己的方法填充完之后,就可以让 sort() 方法按照我们想要的任何一种方式来排序
var arr = [1,3,5,4,10]; arr.sort(function(a, b){ // 匿名函数 });
function 里面必须要写两个形参,而且这个 functin 不用写名字,这就是一个函数引用
这个函数引用,类似于把这个 function 写到外面,把函数名 test 填进去,也是填个引用进去
var arr = [1,3,5,4,10]; arr.sort(test); // 2.函数引用test填进去 function test(){ // 1.函数写在外边 }
所以,function 莫不如直接在里面写了
这个 function 用不着我们自己去调用,把他当做参数传进去,系统会在适当的时候去调用,
只不过我们把 function 里面的规则写好就 OK 了
3、排序规则
function 里面的规则是什么呢?
1. 必须写两个形参
2. 看函数的返回值
1). 当返回值为负数时,那么前面的数放在前面
2). 当返回值为正数,那么后面的数在前面
3). 返回值为 0,不动
var arr = [1, 3, 5, 4, 10]; arr.sort(function (a, b){ return ; });
sort 会把里面的函数会调动无数次(具体多少次是可求的,有兴趣可以自己去求),每次执行的时候,会传里面两个参数
1. 首先第一次调用函数时时候,会把数组的第一位和第二位传进来
第一位是 1
第二位是 3
第一次调用函数时会把 1, 3 传进来,传进来通过一系列规则比较
2. 当返回值为正数的时候,后面的数在前,
比如返回为 return 1
就会让 1, 3 调换位置为 3, 1
[ 3, 1, 5, 4, 10 ]
3. 当返回值为负数的时候,前面的数就在前,1, 3 不变
4. 具体什么时候返回值为正,什么时候返回值为负,就是我们控制的了
var arr = [ 1, 3, 5, 4, 10 ] 传参的顺序
第一轮
第一次传 1 3
第二次传 1 5
第三次传 1 4
第四次传 1 10
第二轮
然后传 3 5
然后传 3 4
然后传 3 10
第三轮 var arr = [ 1, 3, 5, 4, 10 ]
然后传 5 4 4 和 5 位置互换变成 [ 1, 3, 4, 5, 10 ]
然后传 4 10 4 和 10 比较位置不变 [ 1, 3, 4, 5, 10 ]
第四轮
然后传 5 10 [ 1, 3, 4, 5, 10 ]
上面的过程是升序符合冒泡排序的算法
升序就是从小到大 1 2 3 4 ...
接下来定义升序的规则,当 a 大于 b 的时候返回正数 1,否则返回负数 -1
var arr = [1, 3, 5, 4, 10]; arr.sort(function (a, b){ if(a > b){ return 1; }else{ return -1; } }); console.log(arr); // [1, 3, 4, 5, 10]
第一遍传 1 3
1 3 [ 1, 3, 5, 4, 10 ]
1 5 [ 1, 3, 5, 4, 10 ]
1 4 [ 1, 3, 5, 4, 10 ]
1 10 [ 1, 3, 5, 4, 10 ]
第二轮传 3 和 5 比
3 5 [ 1, 3, 5, 4, 10 ]
3 4 [ 1, 3, 5, 4, 10 ]
3 10 [ 1, 3, 5, 4, 10 ]
第三轮传 5 和 4 比
5 4 [ 1, 3, 4, 5, 10 ] 5 大于 4 换位置,后面数在前,两个数换一下位置
4 10 [ 1, 3, 4, 5, 10 ] 然后这个位置的和那个位置的比,不要认数,要认位置,4 跟 10 比小于,小于谁也不动
第四轮传 5 和 10 比
5 10 [ 1, 3, 4, 5, 10 ]
这是升序,我们通过系统留的接口,自定义规则弄出来的升序
再排序一个数组
var arr = [2, 10, 20, 13, 4, 18, 9]; arr.sort(function (a, b){ if(a > b){ return 1; }else{ return -1; } }); console.log(arr); // [2, 4, 9, 10, 13, 18, 20]
2 10 [ 2, 10, 20, 13, 4, 18, 9 ]
2 20 [ 2, 10, 20, 13, 4, 18, 9 ]
2 13 [ 2, 10, 20, 13, 4, 18, 9 ]
2 4 [ 2, 10, 20, 13, 4, 18, 9 ]
2 18 [ 2, 10, 20, 13, 4, 18, 9 ]
2 9 [ 2, 10, 20, 13, 4, 18, 9 ]
10 20 [ 2, 10, 20, 13, 4, 18, 9 ]
10 13 [ 2, 10, 20, 13, 4, 18, 9 ]
10 4 [ 2, 10, 20, 13, 4, 18, 9 ] 4 换到 10 位置
4 18 [ 2, 4, 20, 13, 10, 18, 9 ]
4 9 [ 2, 4, 20, 13, 10, 18, 9 ]
每一轮进行完后,会最小得数放前面
20 13 [ 2, 4, 20, 13, 10, 18, 9 ] 13 换到前面的位置
13 10 [ 2, 4, 13, 20, 10, 18, 9 ] 10 换到前面的位置
10 18 [ 2, 4, 10, 20, 13, 18, 9 ]
10 9 [ 2, 4, 9, 20, 13, 18,10 ] 9 换到前面的位置
前三位按循序了,第四位开始
20 13 [ 2, 4, 9, 20, 13, 18, 10 ] 13 换到前面的位置
13 18 [ 2, 4, 9, 13, 20, 18, 10 ]
13 10 [ 2, 4, 9, 10, 20, 18, 13 ] 10 换到前面的位置
20 18 [ 2, 4, 9, 10, 20, 18, 13 ] 18 换到前面的位置
18 13 [ 2, 4, 9, 10, 18, 20, 13 ] 13 换到前面的位置
13 18 [ 2, 4, 9, 10, 13, 20, 18 ]
20 18 [ 2, 4, 9, 10, 13, 20, 18 ] 18换到前面的位置
18 20 [ 2, 4, 9, 10, 13, 18, 20 ]
这是数组 sort() 方法给我们的一个比较的顺序,比较的原则结合这个比较的顺序,就叫算法里面的冒泡排序,但今天讲的不是冒泡排序是数组的算法。
上面的完后是一个升序,变一下比较规则,当 a 小于 b 时返回降序
var arr = [2, 10, 20, 13, 4, 8, 9]; arr.sort(function(a, b){ // a小于b变降序 if(a < b){ return 1; }else{ return -1; } }); console.log(arr); // [20, 13, 10, 9, 8, 4, 2]
var arr = [ 2, 10, 20, 13, 4, 8, 9 ]
2 10 [ 2, 10, 20, 13, 4, 8, 9 ] 2 小于10 换位置
10 20 [ 20, 2, 10, 13, 4, 8, 9 ] 10 小于20 换位置
20 13 [ 20, 2, 10, 13, 4, 8, 9 ]
20 4 [ 20, 2, 10, 13, 4, 8, 9 ]
20 8 [ 20, 2, 10, 13, 4, 8, 9 ]
20 9 [ 20, 2, 10, 13, 4, 8, 9 ]
2 10 [ 20, 10, 2, 13, 4, 8, 9 ] 2 小于 10,换位置
10 13 [ 20, 13, 2, 10, 4, 8, 9 ] 10 小于 13,换位置
13 4 [ 20, 13, 2, 10, 4, 8, 9 ]
13 8 [ 20, 13, 2, 10, 4, 8, 9 ]
13 9 [ 20, 13, 2, 10, 4, 8, 9 ]
2 10 [ 20, 13, 2, 10, 4, 8, 9 ] 2 小于 10,换位置
10 4 [ 20, 13, 10, 2, 4, 8, 9 ]
10 8 [ 20, 13, 10, 2, 4, 8, 9 ]
10 9 [ 20, 13, 10, 2, 4, 8, 9 ]
2 4 [ 20, 13, 10, 4, 2, 8, 9 ] 2 小于 4,换位置(这步就是已经换了的)
4 8 [ 20, 13, 10, 8, 2, 4, 9 ] 4 小于 8,换位置 (这步就是已经换了的)
8 9 [ 20, 13, 10, 9, 2, 4, 8 ] 8 小于 9,换位置 (这步就是已经换了的)
2 4 [ 20, 13, 10, 9, 4, 2, 8 ] 2 小于 4 换位置 (这步就是已经换了的)
4 8 [ 20, 13, 10, 9, 8, 2, 4 ] 4 小于 8 换位置 (这步就是已经换了的)
2 4 [ 20, 13, 10, 9, 8, 2, 4 ] 2 小于 4 换位置
4 2 [ 20, 13, 10, 9, 8, 4, 2 ]
这一系列换完之后变降序了,通过 a 小于 b 的改变,可以控制升序降序
想让数组升序,换回a大于b
var arr = [2, 10, 20, 13, 4, 8, 9]; arr.sort(function(a, b){ if(a > b){ // a大于b变升序 return 1; }else{ return -1; } }); console.log(arr); // [2, 4, 8, 9, 10, 13, 20]
怎么没计算 0 呢?
0 反正也没变化,算它干嘛呢!
4、简化升序
接下来简化一下,有没有什么通式?
第一个数比第二个数大,才调换位置一定是升序,
a 大 b 小,要把 b 放前面,肯定是升序,能不能总结一个通式?
换一种写法
当 a - b > 0 大于 0 的时候,要返回一个大于 0 的数,就是返回 a - b 的结果就完事了
当 a - b < 0 小于 0 的时候,要返回一个小于 0 的数,直接返回 a - b 的结果就完事了
也就是升序排列
当 a - b 大于 0 的时候,返回 a - b
当 a - b 小于 0 的时候,返回 a - b
var arr = [2,10,20,13,4,18,9]; arr.sort(function(a, b){ if(a - b > 0){ return a - b; }else{ a - b < 0 return a - b; } }); console.log(arr); // [2, 4, 8, 9, 10, 13, 20]
就是无论什么时候返回 a - b 都是升序,
当 a 小于 b 到时候,返回的是一个负数,
当 a 大于 b 的时候,返回到是一个正数还是 a - b
var arr = [2,10,20,13,4,18,9]; arr.sort(function(a, b){ return a - b; // 升序 }); console.log(arr); // [2, 4, 9, 10, 13, 18, 20]
5、简化降序
下面是降序的简化
a 小于 b 的时候返回 1,
a 大于 b 的时候返回 -1
var arr = [2,10,20,13,4,18,9]; arr.sort(function(a, b){ if(a < b){ return 1; }else{ return -1; } }); console.log(arr); // [20, 18, 13, 10, 9, 4, 2]
a 小于 b 就返回 b - a 就行了
a 大于 b 要返回负数还是要返回 b - a
var arr = [2,10,20,13,4,18,9]; arr.sort(function(a, b){ if(a < b){ return b - a; }else{ return b - a; } }); console.log(arr); // [20, 18, 13, 10, 9, 4, 2]
所以 return b - a 是降序
var arr = [2,10,20,13,4,18,9]; arr.sort(function(a, b){ return b - a; // 降序 }); console.log(arr); // [20, 18, 13, 10, 9, 4, 2]
6、练习(面试题)
第一题:
给一个有序数组乱序
原题,随机打乱原数组的顺序,然后在一次性返回。
乱序的结果,就是每次的结果都是不一样的,这次执行和下次执行不一样。
首先先铺垫一下 Math.random() 产生 0 到 1 之间的开区间数 [0, 1),每次都不一样,特别小的小数
console.log(Math.random()); // 0.03409055182865539
Ps:
开区间就是不包括两头的数,不可能到 0 或 1,
闭区间就是包括 0 和 1
返回 0 到 1 之间的随机数,想让它可正数、可负数怎么办?
Math.random() - 0.5 或 0.5 - Math.random()
既然返回的是 0 到 1 之间的开区间数,让 0.5 减去这个开区间数,因为开区间数有可能是 0 到 0.5 之间,也有可能是 0.5 到 1 之间,
这样概率一半一半,有可能正、有可能负,这样每次返回的是随机的值
console.log(0.5 - Math.random());
再用 sort() 方法排序,就是随机乱排了
var arr = [1,2,3,4,5,6,7]; arr.sort(function(){ return Math.random() - 0.5; }); console.log(arr); // 每次结果都不一样
第二题:
把下面对象放到数组里面,按照的对象的年龄排序(升序)
var Fang = { name : "fang", age : 40, sex : "male", face : "amazing" } var Lili = { name : "lili", age : 37, sex : "female", face : "amazing" } var Glee = { name : "Lu", age : 36, sex : "female" } var arr = [Fang, Lili, Glee]; // 把对象放到数组里 arr.sort(function (a ,b){ if(a.age > b.age){ return 1; }else{ return -1; } // 还可以这样简化 return a.age - b.age; }); console.log(arr);
关键知道原理是什么,把参数 a, b 用灵活了,知道原理想怎么排序怎么排
第三题:
按照字符串长度排序
var arr = ['abc', 'bcd', 'ccc', 'dddd', 'asdfkhiuqwe', 'asdoifqwoeiur', 'asdf']; arr.sort(function (a ,b) { return a.length - b.length; }); console.log(arr); //["abc", "bcd", "ccc", "dddd", "asdf", "asdfkhiuqwe", "asdoifqwoeiur"]
第四题:
按照字节长度排
var arr = ['abc莉莉', 'bcd莉', 'c莉', 'dddd莉', 'asdfkhiuqwe莉莉', 'asdoifqwoeiur', 'asdf']; // 先封装一个方法,计算字节的长度 function retBytes(str) { var num = str.length; for (var i = 0; i < str.length; i++) { if (str.charCodeAt(i) > 255) { num++; } } return num; } arr.sort(function(a, b) { return retBytes(a) - retBytes(b); }); console.log(arr); // ["c莉", "asdf", "bcd莉", "dddd莉", "abc莉莉", "asdoifqwoeiur", "asdfkhiuqwe莉莉"]
先写一个 retBytes 方法返回字节长度,小功能实现完之后漫漫拓展,能成为一个很复杂的东西
二、不可以改变原数组的方法
这些方法特别简单 concat, join—>split, toString, slice
8. concat()
concat 方法是链接两个数组,会把后面的数组(arr1)拼到前面的数组(arr)上,并且规则发生了改变。
var arr = [1,2,3,4,5,6]; var arr1 = [7,8,9]; // 拼接 console.log(arr.concat(arr1)); // [1, 2, 3, 4, 5, 6, 7, 8, 9] // 原数组不改变 console.log(arr); // [1, 2, 3, 4, 5, 6] console.log(arr1); // [7, 8, 9]
上面学过的都是能改变原数组的,
这几个 concat, join—>split, toString, slice 是改变不了的,
改变不了的意思是 concat() 拼完是一个全新的数组,不影响原来的两个原数组。concat 是计算机给英语造出来的词链接的意思。
9. toString()
数组的 toString 方法,就是把数组变成字符串展示出来,是数组自己重写的
var arr = [1,2,3,4,5,6]; var str = arr.toString(); console.log(str); // ”1,2,3,4,5,6”
10. slice()
slice 方法是截取和 splice 有点相像又不一样,
slice 里面可以填 0 个参数,可以填一个参数,也可以填两个参数
先看填两个参数的 slice( 从该位开始截取, 截取到该位 ) 不是“截取了”是“截取到”
var arr = [1,2,3,4,5,6]; var newArr = arr.slice(1, 2); // 从第一位的2开始截取,截取到第二位的3,不包括第二位的3 console.log(newArr); // [2] console.log(arr); // [1,2,3,4,5,6]
[ 1, 2, 3, 4, 5, 6]
第零位 第一位 第二位 第三位...
1 是第零位,
2 是第一位,
只截取到第二位的 3
从第一位开始截取,截取到第二位
看原数组还那样 [ 1, 2, 3, 4, 5, 6 ],
不改变原数组,关注的只能是返回值,所以 slice 截取完,千万要拿一个变量接收,否则 slice 没有意义。
从第一位开始截取,截取到第三位呢?
var arr = [1, 2, 3, 4, 5, 6]; var newArr = arr.slice(1 ,3); console.log(newArr); // [2, 3] console.log(arr); // [1, 2, 3, 4, 5, 6]
一个参数的情况是,从第几位开始截取,一直截取到最后
var arr = [1, 2, 3, 4, 5, 6]; var newArr = arr.slice(1); console.log(newArr); // [2, 3, 4, 5, 6]
从第一位开始截取,一直截取到最后返回 [ 2, 3, 4, 5, 6 ]
当然还可以填负数,从负四开始( -4 + 6 = 2 )就是倒数第四位,相当于从正数第二位开始
var arr = [1, 2, 3, 4, 5, 6]; var newArr = arr.slice(-4); console.log(newArr); // [3, 4, 5, 6]
要是不懂负数,直接加 length 就完事了,
当然系统提供负数是为了让我们更好的理解的,-4 就是倒数第四个(倒数直接
不写参数就是整个截取,整个截有用吗?
想把一个“类数组”转化成数组就用 sliec() 空截
var newArr = arr.slice(); console.log(newArr);// [1, 2, 3, 4, 5, 6]
最后一个方法 join —> split
11. join()
这个方法了不得,join() 里面可以传参数,参数传什么都行,但是必须是字符串形式的,传空串也得是字符串
如果传 "-" 它会把数组里的每一位都链接起来并返回一个字符串
var arr = [1,2,3,4,5,6]; var arrStr = arr.join("-"); console.log(arrStr);//1-2-3-4-5-6
它会把数组的每一位都链接起来,按照传的参数去链
var arrStr1 = arr.join("!"); console.log(arrStr1);//1!2!3!4!5!6 var arrStr2 = arr.join("~"); console.log(arrStr2);//1~2~3~4~5~6
12. split()
和 join() 可逆的是 split() 方法,split() 是字符串的方法不是数组的,但它却和数组方法可逆的
split() 方法是按照什么拆分成数组,字符串有方法能拆分能数组,数组有方法能组合成字符串
按照 "-" 来拆分为数组
var str = "1-2-3-4-5-6"; var arr1 = str.split("-"); console.log(arr1);// ["1", "2", "3", "4", "5", "6"]
按那个拆分就把那个给咔嚓了就没了,按 4 拆就截取符了 4 就没了,按照 "-" 拆 "-" 就没了
var arr2 = str.split("4"); console.log(arr2); // ["1-2-3-", "-5-6"]
split() 可以返回数组,
join() 数组可以返回字符串
应用一下,
这个 join 到底是在哪应用的,这么多的字符串形式拼到一起。之前有这么一个面试题,给50个公司的名称,把50个名称拼到一起。
var str = "alibaba"; var str1 = "baidu"; var str2 = "tencent"; var str3 = "toutiao"; var str4 = "wangyi"; var str5 = "xiaowang"; var str6 = "nv";
第一种方法,字符串拼接
var strFinal = str + str1 + str2 + str3 + str4 + str5 + str6; console.log(strFinal);
第二种方法,写到一个数组里面
var arr = [str, str1, str2, str3, str4, str5, str6], len = arr.length, strFinal = ''; for(var i = 0; len > i; i ++){ strFinal += arr[i]; } console.log(strFinal);
原始值字符串在栈里面存储,栈内存有个规则先进后出,
访问栈内存的时候,要拿出来拼到一起,再拿出来拼到一起,来回折腾这个栈,效率肯定低,
所以字符串的链接是一种栈内存的链接,链完之后效率是低的,尽量不用栈内存。
数组是散列存储结构是堆内存,如果把这些东西全放到数组里面去,然后利用数组是通过散列的算法去找,最后用 join() 方法这样效率是高的
var arr = [str, str1, str2, str3, str4, str5, str6]; var strFinal = arr.join("");//这里不需要用什么来链传空串就行,不传arr.join()它默认用逗号链 console.log(strFinal);
Ps:
头条的深度算法,人工智能的推送是最强的。
但凡上头条之后新闻就看不断了,它能把你所喜欢的东西一起全给你。
让你不断的看不断的占用你的精力,而大家普遍喜欢的资源还特别多。
比如女生喜欢购物喜欢时装这种东西你就看去吧,你要认真的话这辈子就这么过去吧!绝对给你推送让你看不完!