携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情
数组排序
参考往期文章排序与搜索算法。
数组去重
方法一
ES6扩展运算符和 Set 结构相结合,就可以去除数组的重复成员
扩展运算符( spread )是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
Set:Es6提供了新的数据结构set。它类似于数组,但是成员的值都是唯一的,没有重复的值。返回值为{}类型。
注:
在 Set 内部,两个 NaN 是相等。
另外,两个对象总是不相等的。
// 去除数组的重复成员
[...new Set([1, 2, 2, 3, 4, 5, 5])];
// 结果为[1, 2, 3, 4, 5]
方法二
利用Array.from()把set结构转换为数组
Array.from()方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例.
Array.from(new Set([1, 2, 2, 3, 4, 5, 5]));
方法三
forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
注意: forEach() 对于空数组是不会执行回调函数的。
注:indexOf() 方法对大小写敏感!
注释:如果要检索的字符串值没有出现,则该方法返回 -1。
var arr = [1,2,3,4,5,4,5]
var temp = [];
arr.forEach(e => {
if (temp.indexOf(e) == -1) {
temp.push(e);
}
});
console.log(temp)
反转数组
有以下要求: 输入: I am a student(数组) 输出: student a am I
输入是数组, 输出也是数组;
不允许用 split splice reverse
方法一
var str = "I am a student ."
var newStr = ""
var newTemp = []
var word = "" var
temp = Array.from(str)
for (var i = 0; i < temp.length; i++) {
word += temp[i]
// if(asc.indexOf(temp[i]) === -1) {
if(temp[i] === " ") {
newTemp.unshift(word)
word = ""
}
}
// 想数组中加入最后一个词,因为最后一个词后面没有空格 newTemp.unshift(word)
// 词之间用空格分隔开
newStr = newTemp.join(" ")
console.log(newStr)
对方法一进行一点改进
function reverseArray(arr) {
let str = arr.join(' ')
let result = [] let word = ''
for (let i = 0; i < str.length; i++) {
if (str[i] != ' ') {
word += str[i]
} else {
result.unshift(word) word = ''
}
}
result.unshift(word)
return result
}
console.log(reverseArray(['I', 'am', 'a', 'student']))
// ["student", "a", "am", "I"]
方法二
function reverseArray(arr) {
let result = [] let
distance = arr.length - 1
for (let i = 0; i <= distance; i++) {
result[i] = arr[distance - i]
}
return result
}
节流
函数节流是减少连续的高频操作函数执行次数 (例如连续调用10次, 可能只执行3-4次)
函数节流是优化高频率执行js代码的一种手段
可以减少高频调用函数的执行次数
作用:减少代码执行次数, 提升网页性能
应用场景:oninput / onmousemove / onscroll / onresize 等事件
封装一个节流函数
function throttle(fn,delay) {
let timer = null
return function (...args) {
if(timer) return
timer = setTimeout( () => {
fn.apply(this,args)
timer = null
},delay)
}
}
防抖
函数防抖是让连续的高频操作时函数只执行一次(例如连续调用10次, 但是只会执行1次)
函数防抖是也优化高频率执行js代码的一种手段
可以让被调用的函数在一次连续的高频操作中只被调用一次
作用:减少代码执行次数, 提升网页性能
应用场景:oninput / onmousemove / onscroll / onresize 等事件
封装一个防抖函数:
注意:方便防抖函数的调用和回调函数fn的传参问题,这里使用闭包来设计防抖函数
function debounce(fn,delay) {
let timer = null
return function (...args) {
timer&&clearTimeout(timer)
timer = setTimeout( () => {
fn.apply(this,args)
},delay)
}
}
深拷贝
class Person{
name = "zs";
cat = {
age : 3
};
score = [1, 3, 5];
}
let p1 = new Person();
let p2 = new Object();
// 通过自定义函数实现深拷贝
function deCopy(target, source) {
// 1.通过遍历拿到source中所有的属性
for (let key in source){
// 2.取出当前遍历到的属性对应的取值
let sourceValue = source[key];
// 3.判断当前的取值是否是引用数据类型
if (sourceValue instanceof Object){
// 如果是引用数据类型, 那么要新建一个存储空间保存
// 4.通过sourceValue.constructor拿到这个对象的构造函数的类型, 然后新建这个对象或数组
let subTarget = new sourceValue.constructor; target[key] = subTarget;
// 5.再次调用拷贝, 将遍历到的属性的取值拷贝给新建的对象或者数组
deCopy(subTarget, sourceValue);
}else {
// 如果不是引用数据类型, 之间将属性拷贝即可
target[key] = sourceValue;
}
}
}
可以利用递归将上述深拷贝进行简化:
// 简化版本
function deCopy(obj){
// 如果不是引用数据类型, 直接将属性拷贝即可
if(typeof obj != 'object') return obj
// 如果是引用数据类型, 那么要新建一个存储空间保存
let newObj = new obj.constructor
for(let key in obj){
// 递归调用拷贝, 将遍历到的属性的取值拷贝给新建的对象或者数组
newObj[key] = deCopy(obj[key])
}
return newObj
}
deCopy(p2, p1);
p2.cat.age = 666; // 修改新变量的值不会影响到原有变量, 这里是深拷贝
console.log(p1.cat.age);
// 3 console.log(p2.cat.age); // 666
数组扁平化
假如有一个数组 var arr = [1, [2, 3, [4]]] ,把arr变成[1, 2, 3, 4]?即让多维数组降维,转换为只有一层的数组;即为数组扁平化。
方法一
循环数组+递归
概念:可以理解为将嵌套数组的维数减少。
function flatten(arr){
var result = [];
for(var i = 0, len = arr.length; i < len; i++){
if(Array.isArray(arr[i])){
result = result.concat(flatten(arr[i]));
}else{
result.push(arr[i]);
}
}
return result;
}
flatten(arr)
// [1,2,3,4]
方法二
使用apply实现数组扁平化
实现思路:利用数组方法some判断当数组中还有数组的话,递归调用flatten扁平函数(利用apply实现扁平), 用concat连接,最终返回arr;
some:对数组中的每个元素都执行一次指定的函数(callback),直到此函数返回 true,如果发现这个元素,some 将返回 true,如果回调函数对每个元素执行后都返回 false ,some 将返回 false。
concat: 如果concat方法的参数是一个元素,该元素会被直接插入到新数组中;如果参数是一个数组,该数组的各个元素将被插入到新数组中。
apply:apply方法会调用一个函数,apply方法的第一个参数会作为被调用函数的this值,apply方法的第二个参数(一个数组,或类数组的对象)会作为被调用对象的arguments值,也就是说该数组的各个元素将会依次成为被调用函数的各个参数;作为apply方法的第二个参数,本身是一个数组,数组中的每一个元素(还是数组,即二维数组的第二维)会被作为参数依次传入到concat中。利用apply方法,我们将单重循环优化为了一行代码
function flatten(arr){
while(arr.some(item => Array.isArray(item))){
arr = [].concat.apply([],arr);
} return arr;
}
flatten(arr)
// [1,2,3,4]
方法三
使用reduce数组方法
实现思路:使用reduce, 当数组中还有数组的话,递归调用flatten扁平函数(利用reduce扁平), 用concat连接,最终返回arr.reduce的返回值;
arr.reduce(callback,[initialValue]),reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。initialValue作为第一次调用callback的第一个参数
function flatten(arr){
return arr.reduce(function(prev, cur){
return prev.concat(Array.isArray(cur) ? flatten(cur) : cur)
},[])
}
flatten(arr)
// [1,2,3,4]
方法四
使用ES6展开运算符
实现思路:利用数组方法some判断当数组中还有数组的话,递归调用flatten扁平函数(利用ES6展开运算符扁平), 用concat连接,最终返回arr;
function flatten(arr){
while(arr.some(item => Array.isArray(item))){
arr = [].concat(...arr);
}
return arr;
}
flatten(arr)
// [1,2,3,4]
方法五
使用toString方法,仅适用于数组元素为数字的情况。
function flatten(arr){
return arr.toString().split(',').map(function(item){
return parseInt(item);
})
}
flatten(arr)
// [1,2,3,4]
函数柯里化(curry)
柯里化:把接收多个参数的函数变换成接收一个单一参数的函数(单一参数为多个参数中的第一个), 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。如:
var add = function(x) {
return function(y) {
return x + y;
};
};
var increment = add(1);
var addTen = add(10);
increment(2);
// 3
addTen(2);
// 12
add(1)(2);
// 3
函数柯里化思想:一个JS预处理的思想,降低通用性,提高适用性。
最后
本文也是本人的学习笔记,有教程代码,也有本人自己写的代码,可供参考。