一、数组去重
数组去重是一个很常见的需求了,在网上也有很多去重的方法,在此介绍两个简洁的去重方法。
unique(arr){
if(!Array.isArray(arr))
throw new Error("arr is not a array")
return [...new Set(arr)] //或者 Array.from(new Set(arr))
}
上面就是利用了 Set 元素的唯一性。
但是,如果数组中存在内容相同的引用类型,那么这个方法就没有效果了。
比如:
let arr = [
{name:"jonas",age:18},
{name:"jonas",age:18},
{name:"jonas",age:18}
]
你会发现无论使用上面的方法还是网络上介绍的数组去重方法,都实现不了这种去重。所以,这时候自己写了一个方法用于解决这个问题(见下面)。
二、数组深度去重
对于基本数据类型的去重很简单,就是上面的一行代码就解决了,然而复杂的是引用类型。此处的引用类型主要是指对象和数组,所以,问题就变成两个:①去重内容相同的对象②去重内容相同的数组。
因为数组和对象的特征不同,存储数据的方式也不同,所以第一件事就是将数组和对象区分开来。
/**
-
获取一个值的类型
-
@param target
-
@returns {string} 返回这个值的类型。如果是数组,则返回 "Array";是对象返回 "Object"
*/
function getType(target) {
return Object.prototype.toString.call(target).slice(8,-1)
}
接下来的问题就是判断两个对象中的内容是否完全一致了。
/**
-
判断两个对象的内容是否完全一致,返回布尔值
-
@param a
-
@param b
-
@returns {boolean}
*/
function objUnique(a,b) {
//限制两个参数都是对象
if(getType(a) !== 'Object' && getType(b) !== 'Object')
return false
//获取其中一个对象的属性
let keyList = Object.keys(a)
for(let i = 0;i < keyList.length;i++){
//获取键名
let propName = keyList[i]
//处理嵌套
if(getType(a[propName]) === 'Object' && getType(b[propName]) === 'Object'){
objUnique(a[propName],b[propName])
}else if(getType(a[propName]) === 'Array' && getType(b[propName]) === 'Array'){
arrUnique(a[propName],b[propName])
}else if(a[propName] !== b[propName]){
//存在一对键值对不同,则表示两个对象不同
return false
}
}
return true
}
/**
-
判断两个数组的内容是否完全一致,返回布尔值
-
@param a
-
@param b
-
@returns {boolean}
*/
function arrUnique(a, b) {
//限制两个参数都是数组
if(getType(a) !== 'Array' && getType(b) !== 'Array')
return false
//如果长度不等,则两个数组不可能相同
if(a.length !== b.length)
return false
//处理嵌套
for(let i = 0;i < a.length;i++){
if(getType(a[i]) === 'Object' && getType(b[i]) === 'Object'){
objUnique(a[i],b[i])
}else if(getType(a[i]) === 'Array' && getType(b[i]) === 'Array'){
arrUnique(a[i],b[i])
}else if(a[i] !== b[i]){
//存在一个元素不同,则表示两个数组不同
return false
}
}
return true
}
整合:
/**
-
数组深度去重
-
@param arr
-
@returns {null|*[]}
*/
function unique(arr) {
//处理异常参数
if(getType(arr) !== 'Array')
throw new Error("arr is not a Array.")
//基本数据类型容器
let commonList = []
//对象收纳容器
let objList = []
//数组收纳容器
let arrList = []
//数据分类
arr.forEach(item => {
if(getType(item) === 'Object'){
objList.push(item)
}else if(getType(item) === 'Array'){
arrList.push(item)
}else{
commonList.push(item)
}
})
//基本数据类型去重
commonList = Array.from(new Set(commonList))
//对象收纳容器去重
for(let i = 0;i < objList.length;i++){
for(let j = i + 1;j < objList.length;j++){
if(objUnique(objList[i],objList[j])){
objList.splice(j,1)
j--
}
}
}
//数组收纳容器去重
for(let i = 0;i < arrList.length;i++){
for(let j = i + 1;j < arrList.length;j++){
if(arrUnique(arrList[i],arrList[j])){
arrList.splice(j,1)
j--
}
}
}
//合并收纳容器
return [...commonList,...objList,...arrList]
}
三、数组的并集,交集,差集
公共代码:
let arr1 = [1, 2, 3]
let arr2 = [4, 3, 2]
①并集
let arr = [...new Set([...arr1,...arr2])]
②交集
let arr = arr1.filter(x => arr2.includes(x))
③差集
let arr = arr1.filter(x => !arr2.includes(x))
四、取数组中的最大值与最小值
/**
-
取数组中的最大值与最小值,忽略非数值元素和NaN
-
@param arr
-
@return {{min: *, max: *}|null}
*/
function minAndMax(arr) {
//规范类型
function getType(obj) {
return Object.prototype.toString.call(obj).slice(8,-1)
}
if(getType(arr) !== "Array")
throw new Error("arr is not array")
let min
let max
let flag = 0
for(let i = 0;i < arr.length;i++){
let current = arr[i]
//剔除非法数据
if(getType(current) !== "Number" || Number.isNaN(current)){
continue
}
if(!flag){
min = current
max = current
flag++
}
if(current > max)
max = current
if(current < min)
min = current
}
return {min,max}
}
五、数组的扁平化
扁平化,就是将多维数组转换为一维数组。
在 ES6 中有提供了一个方法用于扁平化:
let arr = [1,[2,[3,[4]]]]
let result = arr.flat(Infinity) //参数代表扁平层数,默认为1
一、对象或数组的深拷贝
JSON.parse(JSON.stringify(obj))
一、准确检测数据类型
无论是 typeof 还是 instanceof ,都无法很好的准确的检测一个未知对象的数据类型。所以还是手写了一个方法:
/**
-
检测数据类型
-
@param obj 待检测对象
-
@returns {string} 返回具体的类型(首字母大写)
*/
function checkType(obj) {
return Object.prototype.toString.call(obj).slice(8,-1)
}
- 如果是对象,则返回
Object;
ajax
1)ajax请求的原理/ 手写一个ajax请求? 2)readyState? 3)ajax异步与同步的区别? 4)ajax传递中文用什么方法?