1、影响原数组的方法
push(): 向数组末尾添加一个或多个元素。
pop(): 删除数组末尾的元素,并返回被删除的元素。
shift(): 删除数组头部的元素,并返回被删除的元素。
unshift(): 向数组头部添加一个或多个元素。
splice(): 根据索引删除指定位置的元素,并可选地插入新的元素。
sort(): 排序数组中的元素。
reverse(): 颠倒数组中的元素的顺序。
es6中数组的扩展有,解构赋值、扩展运算符...、includes、find,findIndex、Array.from()、Array.of()
2、typeof常见题目:
toypeof null的值OBject
3、数字和字符串类型转换
1、数字转字符串
Number类定义的toString()方法
Number类定义的toFixed()方法
使用String()函数:
2、字符串转数字
通过Number()转换函数
parseInt()函数
parseFloat()函数
4、正则表达式基本:
* :出现零到多次
+: 出现一到多次
?:出现零次或者一次
. : 除了\n以外的任意字符
{n} : 出现n次
{n,} : 出现n到多次
{n,m} : 出现n到m次
5、++x是前置自增,也就是先自增加1,再将x返回
6、深拷贝实现
手写递归方法:(递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝)
function cloneDeep(obj) {
//数据类型为引用数据类型
if (typeof obj == 'object') {
//初始化返回结果
let result = Array.isArray(obj) ? [] : {};
fot(let key in obj) {
//避免相互引用出现死循环导致爆栈
if (obj === obj[key]) {
continue
}
if (obj.hasOwnProperty(key)) {
//递归调用
result[key] = deepClone(obj[key])
}
}
return result
} else {
//基本数据类型,直接返回
return obj
}
}
//下面是各种都考虑到了
function deepCopy(obj, parent = null) {
// 创建一个新对象
let result = {};
let keys = Object.keys(obj),
key = null,
temp = null,
_parent = parent;
// 该字段有父级则需要追溯该字段的父级
while (_parent) {
// 如果该字段引用了它的父级则为循环引用
if (_parent.originalParent === obj) {
// 循环引用直接返回同级的新对象
return _parent.currentParent;
}
_parent = _parent.parent;
}
for (let i = 0; i < keys.length; i++) {
key = keys[i];
temp = obj[key];
// 如果字段的值也是一个对象
if (temp && typeof temp === 'object') {
// 递归执行深拷贝 将同级的待拷贝对象与新对象传递给 parent 方便追溯循环引用
result[key] = DeepCopy(temp, {
originalParent: obj,
currentParent: result,
parent: parent
});
} else {
result[key] = temp;
}
}
return result;
}
还有问题:子对象互相引用的情况没有解决
7、版本号对比实现
function compareVersion(version1, version2) {
const v1 = version1.split('.');
const v2 = version2.split('.');
for (let i = 0; i < v1.length || i < v2.length; i++) {
let x = 0, y = 0;
if (i < v1.length) {
x = parseInt(v1[i]);
}
if (i < v2.length) {
y = parseInt(v2[i])
}
if (x > y) return 1;
if (x < y) return -1;
}
return 0;
}
let v1 = '3.34.5', v2 = '3.27.10';
console.log(compareVersion(v1, v2));
8、严格等于非严格等于与Object.is():
下列表达式中,返回值为true的是()
①Object.is(NaN,NaN)
②Object.is(+0,-0)
③NaN === NaN
④+0 === -0
A
①④
9、防抖
防抖的实现原理是,当事件被触发 n 秒后才会执行回调函数,如果在这 n 秒内该事件又被触发,则重新计时。这种方法可以有效防止事件的过多触发,常用于输入框搜索和滚动事件等。
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
};
}
// 调用方式
const debounceFn = debounce(function() {
console.log('debounce');
}, 1000);
document.addEventListener('scroll', debounceFn);
我们定义了函数 debounce,它接受两个参数,一个是回调函数 func,一个是等待时间 wait。返回的是一个匿名函数。在匿名函数内部,我们定义了变量 timeout,用于保存定时器的返回值。当事件被触发时,我们清除该定时器,并重新设置一个新的定时器以达到延迟执行的效果。最后返回的是一个函数,该函数每次执行时都会先清除定时器,然后再设置一个新的定时器,来达到防抖的效果。
10、节流
节流的原理是规定在一个单位时间内,只能触发一次函数。如果这个时间段内触发多次函数,只有一次能生效。常用于滚动事件、resize 事件等。
function throttle(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
if (!timeout) {
timeout = setTimeout(function() {
func.apply(context, args);
timeout = null;
}, wait);
}
};
}
// 调用方式
const throttleFn = throttle(function() {
console.log('throttle');
}, 1000);
document.addEventListener('scroll', throttleFn);
我们定义了函数 throttle,它接受两个参数,一个是回调函数 func,一个是等待时间 wait。返回的是一个匿名函数。在匿名函数内部,我们定义了变量 timeout,用于保存定时器的返回值。当事件被触发时,如果定时器不存在,则创建一个新的定时器,并在单位时间结束后执行回调函数,否则不做任何处理。最后返回的是一个函数,该函数每次执行时会判断定时器是否存在,只有不存在时才会创建新的定时器。
11、递归
递归是一种函数调用自身的方式。在算法和数据结构中经常用到。
function fibonacci(n) {
if (n < 2) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(10)); // 55
使用递归将多为数组对象转化为一维数组对象,详细代码如下:
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 函数中通过 for 循环遍历数组中的每一项,如果当前项是一个数组,
就递归调用 flatten 函数再次将其展开;否则就将当前项 push 到结果数组中。例子如下
var arr = [1, [2, [3, 4], 5], 6];
var result = flatten(arr);
console.log(result); // [1, 2, 3, 4, 5, 6]
我们定义了函数 fibonacci,它接受一个参数 n,表示要求得 fibonacci 的第 n 项。当 n 小于 2 时,直接返回 n,否则返回前两项之和。该函数在执行时会不断调用自身,直到 n 小于 2 为止。这就是递归的基本实现方式。
12、数据去重
数据去重是指去除重复的数据。在开发中,常用于数组去重等场景。
方法一:使用 Set
const arr = [1, 1, 2, 2, 3, 4, 4, 5];
const set = new Set(arr);
const result = Array.from(set);
console.log(result); // [1, 2, 3, 4, 5]
我们将数组转换成了 Set 类型,并将 Set 转成了数组,得到了去重后的结果。
方法二:使用 filter
const arr = [1, 1, 2, 2, 3, 4, 4, 5];
const result = arr.filter(function(item, index, array) {
return array.indexOf(item) === index;
});
console.log(result); // [1, 2, 3, 4, 5]
这里我们使用了 filter 函数,它有三个参数分别为当前元素、当前元素索引和原数组。在 filter 函数内部,我们使用数组的 indexOf 方法来判断当前元素是否已经存在于数组中,如果是则返回 true,否则返回 false。最终过滤出的结果即为去重后的数组。
13、数据排序
数据排序是指将数据按照一定的规则进行排序。在开发中,我们常用的排序算法有冒泡排序、快速排序、归并排序等。
冒泡排序
function bubbleSort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
const tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
return arr;
}
const arr = [3, 2, 5, 4, 1];
console.log(bubbleSort(arr)); // [1, 2, 3, 4, 5]
我们定义了函数 bubbleSort,它接受一个数组 arr,并使用嵌套循环的方式实现了冒泡排序。在内层循环中,我们使用 if 语句来判断相邻的两个元素的大小,如果前面的元素比后面的元素大,则交换它们的位置。在内层循环结束后,我们得到了最大的元素,它被放在了数组的最后面。然后我们再进行下一轮循环,直到所有的轮次循环完成。
快速排序
function quickSort(arr) {
if (arr.length <= 1) {
return arr;
}
const pivotIndex = Math.floor(arr.length / 2);
const pivot = arr.splice(pivotIndex, 1)[0];
const left = [];
const right = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot], quickSort(right));
}
const arr = [3, 2, 5, 4, 1];
console.log(quickSort(arr)); // [1, 2, 3, 4, 5]
我们定义了函数 quickSort,它接受一个数组 arr
14、统计字符串中字符出现最多的字符以及相应的数量
var str = "stiabsstringapbs";
var obj = {};
for (var i = 0; i < str.length; i++) {
var key = str[i];
if (!obj[key]) {
obj[key] = 1;
} else {
obj[key]++;
}
}
var max = -1;
var max_key = "";
var key;
for (key in obj) {
if (max < obj[key]) {
max = obj[key];
max_key = key;
}
}
alert("max:"+max+" max_key:"+max_key);