1. 多维数组降维的几种方法?
1、数组字符串化
let arr = [
[222, 333, 444],
[55, 66, 77]
]
arr += ''
arr = arr.split(',')
console.log(arr) // ['222', '333', '444', '55', '66', '77']
2、递归
function reduceDimension(arr) {
let ret = []
let toArr = function (arr) {
arr.forEach(function (item) {
item instanceof Array ? toArr(item) : ret.push(item)
})
}
toArr(arr)
return ret
}
3、Array.prototype.flat()
var arr1 = [1, 2, [3, 4]]
arr1.flat() // [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]]
arr2.flat() // [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]]
arr3.flat(2) // [1, 2, 3, 4, 5, 6]
// 使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity) // [1, 2, 3, 4, 5, 6]
4、使用 stack 无限反嵌套多层嵌套数组
var arr1 = [1, 2, 3, [1, 2, 3, 4, [2, 3, 4]]]
function flatten(input) {
const stack = [...input]
const res = []
while (stack.length) {
// 使用 pop 从 stack 中取出并移除值
const next = stack.pop()
if (Array.isArray(next)) {
// 使用 push 送回内层数组中的元素,不会改动原始输入 original input
stack.push(...next)
} else {
res.push(next)
}
}
// 使用 reverse 恢复原数组的顺序
return res.reverse()
}
flatten(arr1) // [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
5、使用 reduce、concat 和递归无限反嵌套多层嵌套的数组
var arr1 = [1, 2, 3, [1, 2, 3, 4, [2, 3, 4]]]
function flattenDeep(arr1) {
return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), [])
}
flattenDeep(arr1) // [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
2. 怎么判断两个对象相等?
ES6 中有一个方法判断两个对象是否相等,这个方法判断是两个对象引用地址是否一致
let obj1 = {
a: 1
}
let obj2 = {
a: 1
}
console.log(Object.is(obj1, obj2)) // false
let obj3 = obj1
console.log(Object.is(obj1, obj3)) // true
console.log(Object.is(obj2, obj3)) // false
当需求是比较两个对象内容是否一致时就没用了。
想要比较两个对象内容是否一致,思路是要遍历对象的所有键名和键值是否都一致:
1、判断两个对象是否指向同一内存
2、使用 Object.getOwnPropertyNames 获取对象所有键名数组
3、判断两个对象的键名数组是否相等
4、遍历键名,判断键值是否都相等
let obj1 = {
a: 1,
b: {
c: 2
}
}
let obj2 = {
b: {
c: 3
},
a: 1
}
function isObjectValueEqual(a, b) {
// 判断两个对象是否指向同一内存,指向同一内存返回 true
if (a === b) return true
// 获取两个对象键值数组
let aProps = Object.getOwnPropertyNames(a)
let bProps = Object.getOwnPropertyNames(b)
// 判断两个对象键值数组长度是否一致,不一致返回 false
if (aProps.length !== bProps.length) return false
// 遍历对象的键值
for (let prop in a) {
// 判断 a 的键值,在 b 中是否存在,不存在,返回 false
if (b.hasOwnProperty(prop)) {
// 判断 a 的键值是否为对象,是则递归,不是对象直接判断键值是否相等,不相等返回 false
if (typeof a[prop] === 'object') {
if (!isObjectValueEqual(a[prop], b[prop])) return false
} else if (a[prop] !== b[prop]) {
return false
}
} else {
return false
}
}
return true
}
console.log(isObjectValueEqual(obj1, obj2)) // false
3. 什么是类数组(伪数组),如何将其转化为真实的数组?
伪数组
1、具有 length 属性
2、按索引方式存储数据
3、不具有数组的 push.pop 等方法伪数组(类数组):无法直接调用数组方法或期望 length 属性有什么特殊的行为,不具有数组的 push.pop 等方法,但仍可以对真正数据遍历方法来遍历它们。典型的是函数 document.childnodes 之类的,它们返回的 nodeList 对象都属于伪数组
伪数组转化为真实数组的方法
1、使用 Array.from()--ES6
2、[].slice.call(eleArr) 或则 Array.prototype.slice.call(eleArr)
let eleArr = document.querySelectorAll('li')
Array.from(eleArr).forEach(function (item) {
alert(item)
})
let eleArr = document.querySelectorAll('li')
let arr = []
arr.slice.call(eleArr).forEach(function (item) {
alert(item)
})
4. 如何遍历对象的属性?
1、遍历自身可枚举的属性 (可枚举,非继承属性) Object.keys() 方法
该方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中的属性名的排列顺序和使用 for..in 遍历该对象时返回的顺序一致(两者的区别是 for ..in 还会枚举其原型链上的属性 )
/** Array 对象 **/
var arr = ['a', 'b', 'c']
console.log(Object.keys(arr)) // ['0','1','2']
/** Object 对象 **/
var obj = {
foo: 'bar',
bar: 42
}
console.log(Object.keys(obj)) // ["foo","bar"]
/** 类数组对象 随机 key 排序 **/
var anObj = {
100: 'a',
2: 'b',
7: 'c'
}
console.log(Object.keys(anObj)) // ['2','7','100']
/** getFoo 是一个不可枚举的属性 **/
var my_obj = Object.create({}, {
getFoo: {
value: function () {
return this.foo
}
}
})
my_obj.foo = 1
console.log(Object.keys(my_obj)) // ['foo']
2、遍历自身的所有属性(可枚举,不可枚举,非继承属性) Object.getOwnPropertyNames() 方法
该方法返回一个由指定对象的所有自身属性组成的数组(包括不可枚举属性但不包括 Symbol 值作为名称的属性)
// 数组
var arr = ["a", "b", "c"]
console.log(Object.getOwnPropertyNames(arr).sort()) // ['0', '1', '2', 'length']
// 类数组对象
var obj = {
0: "a",
1: "b",
2: "c"
}
console.log(Object.getOwnPropertyNames(obj).sort()) // ['0', '1', '2']
// 使用 Array.forEach 输出属性名和属性值
Object.getOwnPropertyNames(obj).forEach(function (val, idx, array) {
console.log(val + " -> " + obj[val])
})
// 输出
// 0 -> a
// 1 -> b
// 2 -> c
// 不可枚举属性
var my_obj = Object.create({}, {
getFoo: {
value: function () {
return this.foo;
},
enumerable: false
}
})
my_obj.foo = 1
console.log(Object.getOwnPropertyNames(my_obj).sort()) // ["foo", "getFoo"]
3、遍历可枚举的自身属性和继承属性 (可枚举,可继承的属性) for in 遍历对象的属性
注:hasOwnProperty()方法判断对象是有某个属性(本身的属性,不是继承的属性)
var obj = {
name: '张三',
age: '24',
getAge: function () {
console.log(this.age)
}
}
var arry = {}
for (var i in obj) {
if (obj.hasOwnProperty(i) && obj[i].typeOf != 'function') {
arry[i] = obj[i]
}
}
console.log(arry) // {name: '张三', age: '24', getAge: ƒ}
4、遍历所有的自身属性和继承属性
(function () {
var getAllPropertyNames = function (obj) {
var props = []
do {
props = props.concat(Object.getOwnPropertyNames(obj))
} while (obj = Object.getPrototypeOf(obj))
return props;
}
var propertys = getAllPropertyNames(window)
alert(propertys.length) // 1068
alert(propertys.join("\n")) //Object 等
})()
5. 如何实现数组的随机排序?
方法一:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
function randSort1(arr) {
for (var i = 0, len = arr.length; i < len; i++) {
var rand = parseInt(Math.random() * len)
var temp = arr[rand]
arr[rand] = arr[i]
arr[i] = temp
}
return arr
}
console.log(randSort1(arr))
方法二:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
function randSort2(arr) {
var mixedArray = []
while (arr.length > 0) {
var randomIndex = parseInt(Math.random() * arr.length)
mixedArray.push(arr[randomIndex])
arr.splice(randomIndex, 1)
}
return mixedArray
}
console.log(randSort2(arr))
方法三:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
arr.sort(function () {
return Math.random() - 0.5
})
console.log(arr)