一、数组扁平化
将嵌套多层的数组转化为单层的数组,即将所有元素提取出来放到一个新的数组中。
实现方式可以使用递归或者循环嵌套等方式。
例如,将 [1, [2, 3], [4, [5, 6, [7, 8]]]] 转化为 [1, 2, 3, 4, 5, 6, 7, 8]。
递归实现方式如下:
function flatten(arr) {
var res = []
for (var i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
res = res.concat(flatten(arr[i]))
} else {
res.push(arr[i])
}
}
return res
}
var arr = [1, [2, 3], [4, [5, 6, [7, 8]]]]
console.log(flatten(arr)) // [1, 2, 3, 4, 5, 6, 7, 8]
循环嵌套实现方式如下:
function flatten(arr) {
var res = []
while (arr.length) {
var item = arr.shift()
if (Array.isArray(item)) {
arr = item.concat(arr)
} else {
res.push(item)
}
}
return res
}
var arr = [1, [2, 3], [4, [5, 6, [7, 8]]]]
console.log(flatten(arr)) // [1, 2, 3, 4, 5, 6, 7, 8]
二、字符串
1. 统计一个字符串中某个字符出现的次数?
function sum(str, a) {
let b = str.indexOf(a);
var num = 0;
while (b !== -1) {
console.log(b);
num++;
b = str.indexOf(a, b + 1)
}
return num;
}
2. 统计一个字符串中,出现次数最多的字符,出现了多少次?
方法一:
str = 'asdasddsfdsfadsfdghdadsdfdgdasd'
str = str.split('');
console.log(str);
var newStr = {};
// 数组去重 和计算出现的次数
str.forEach(function (item) {
if (newStr[item]) {
newStr[item]++;
} else {
newStr[item] = 1;
}
})
var max=0;
var strkey=null;
for(var key in newStr){
if(newStr[key]>max){
max=newStr[key];
strkey=key;
}
}
console.log("最多的字符是" + strkey);
console.log("出现的次数是" + max);
方法二:
// 统计一个字符,中出现次数最多的字符。
var str = "zhaochucichuzuiduodezifu";
var o = {};
for (var i = 0, l = str.length; i < l; i++) {
// var char = str[i];
var char = str.charAt(i);
if (o[char]) { //char就是对象o的一个属性,o[char]是属性值,o[char]控制出现的次数
o[char]++; //次数加1
} else {
o[char] = 1; //若第一次出现,次数记为1
}
}
console.log(o); //输出的是完整的对象,记录着每一个字符及其出现的次数
//遍历对象,找到出现次数最多的字符和次数
var max = 0;
var maxChar = null;
for (var key in o) {
if (max < o[key]) {
max = o[key]; //max始终储存次数最大的那个
maxChar = key; //那么对应的字符就是当前的key
}
}
console.log("最多的字符是" + maxChar);
console.log("出现的次数是" + max);
三、深拷贝浅拷贝
深拷贝和浅拷贝的区别
1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用
2.深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”
为什么要使用深拷贝?
我们希望在改变新的数组(对象)的时候,不改变原数组(对象)
内存模型
JS内存空间分为栈(stack)、堆(heap)、池(一般也会归类为栈中)。 其中栈存放变量,堆存放复杂对象,池存放常量。
基本数据类型与栈内存
JS中的基础数据类型,这些值都有固定的大小,往往都保存在栈内存中(闭包除外),由系统自动分配存储空间。我们可以直接操作保存在栈内存空间的值,因此基础数据类型都是按值访问 。 基础数据类型: Number String Null Undefined Boolean
引用数据类型与堆内存
JS的引用数据类型,比如数组Array,它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JS不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以粗浅地理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联。
为了更好的搞懂栈内存与堆内存,我们可以结合以下例子与图解进行理解。
数组的浅拷贝(只拷贝第一级数组元素)
1 .直接遍历
2 . slice()
var array = [1, 2, 3, 4];
var copyArray = array.slice();
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]
3 . concat()
var array = [1, 2, 3, 4];
var copyArray = array.concat();
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]
深拷贝
1. 先转换成字符串,在转换成(数组/对象) JSON.parse(JSON.stringify(XXXX))
var array = [
{ number: 1 },
{ number: 2 },
{ number: 3 }
];
var str = JSON.stringify(array);
var copyArray = JSON.parse(str)
copyArray[0].number = 100;
console.log(array); // [{number: 1}, { number: 2 }, { number: 3 }]
console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]
2 .手动写递归
function deepClone(obj = {}) {
if (typeof obj !== 'object' || obj == null) {
// obj 是 null ,或者不是对象和数组,直接返回
return obj
}
// 初始化返回结果
let result
if (obj instanceof Array) {
result = []
} else {
result = {}
}
for (let key in obj) {
// 保证 key 不是原型的属性
if (obj.hasOwnProperty(key)) {
// 递归调用!!!
result[key] = deepClone(obj[key])
}
}
// 返回结果
return result
}