目录
前言
以下是针对我知识点薄弱的地方进行的总结,为面试的一些基础知识进行复习
一、JS知识点
一、找出数组中的最大值
1.1 使用Math.max.apply
Math.max用于找出传入参数的最大值,而apply可以将数组形式作为参数传入
math.max(a, b ,c, d,...)返回最大的那个数字,其中比较的参数可以任意个
const arr = [1, 2, 45, 6];
console.log(Math.max.apply(null, arr)); //45 apply接受两个参数,第一个用于指定上下文对象,第二个则是数组形式传入参数
1.2 使用Math.max()和扩展运算符
const arr = [1, 2, 45, 6];
console.log(Math.max(...arr)); //45
1.3 使用Math.max()和reduce()
const arr = [1, 2, 45, 6];
const max = arr.reduce((a, b) => Math.max(a, b));
console.log(max);//45
1.4 使用sort()排序
sort方法默认按照字符的ASCII码进行升序排序,所以有时候顺序会不同于想要的结果此时可以将传参改为函数,利用函数返回来决定sort是升序还是降序
const arr = [1, 2, 45, 6];
arr.sort((a, b) => {
return a - b;
});
console.log(arr); //[1,2,6,45]
const max = arr[arr.length - 1];
console.log(max);//45
1.5 使用数组的for循环方法
const arr = [1, 2, 45, 6];
let max = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
console.log(max);//45
二、排序算法
2.1 选择排序
//选择排序
const arr = [8, 7, 3, 9, 12, 5];
//第一轮
//假设最小值是索引值为0的值,如果发现有比当前数更小的数,就重新确定最小数,并得
到下标当遍历到数组的最后时,就得到本轮最小数的小标
//首先i=0不满足条件,i变为1,此时arr[0]>arr[1]即8>7满足条件,此时minIndex=1,
//i变为2,if语句arr[1]>arr[2]即7>3成立,minIndex=2,以此类推后面没有数比3小
//所以第一轮找到的最小值索引为2,与初始值0所在的值交换
let minIndex = 0;
for (let i = 0; i < arr.length - 1; i++) {
if (arr[minIndex] > arr[i]) {
minIndex = i;
}
}
//遍历结束找到当前最小值所在的索引值,让第0个和索引值minIndex的交换
//第二轮则从索引值为i+1开始比较,往后以此类推
var temp = arr[minIndex];
arr[minIndex] = arr[0];
arr[0] = temp;
//结果
// 外层循环表示总共需要排序几次才能找到最小值 第一轮是索引0-arr.length-1
//第二轮是索引1到arr.length-1,....,需要排序的次数是arr.length-1次
//内存循环则为
for (let i = 0; i < arr.length - 1; i++) {
let minIndex = i;
let min = arr[minIndex];
for (let j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {
minIndex = j;
min = arr[j];
}
}
//结束循环后
if (minIndex !== i) {
arr[minIndex] = arr[i];
arr[i] = min;
}
}
// 输出结果: [3, 5, 7, 8, 9, 12]
三、内存泄露
内存泄漏是指程序中不再使用的内存没有被释放,无法进行垃圾回收,从而导致系统内存的浪费,影响系统的性能和稳定性。
3.1 常见的内存泄漏
1、 意外的全局变量。未被声明的变量,会被挂在window对象下,不能及时的销毁。(不使用时将变量设为null)
2、启动循环定时器后不清理,会一直循环。导致计时器持续运行,占用内存空间,导致内存泄漏。(销毁生命周期函数时调用清除定时器的方法)
3、闭包,一个函数在作用域内可以访问另一个函数的变量,这个函数被引用着不会被销毁。(将函数设为null)
四、模块化导入导出
4.1 commonjs
导出分为module.exports和export,导入是require
1.module.exports导出
//a.js导出
module.exports = {a: 1};
//导入
const { a } = require('./a.js')
2.exports导出
nodejs为每个模块提供了一个exposrts变量,其指向module.exports,相当于再模块头部加了这句代码:var exports = module.exports;在对外输出时,可以给exports对象添加方法,但不能直接赋值,因为这样会切断exports与module.exports的联系。所以不能使用exports={}导出,而是如下
exports.a = 1;
exports.fa = function () {};
五、entries()方法
可以将数组转换成一个可迭代数组
const arr = [1, 2, 3];
console.log(arr.entries());
for (let i of arr.entries()) {
console.log(i);
}
//输出
[0,1]
[1,2]
[2,3]
六、如何判断两个对象是否相等
1.使用全等===判断是否相等
===比较的是引用地址,可以判断是否引用了同一个对象,也就是引用地址指向同一个时,可以判断全等。
//使用全等===判断是否相等
const obj1 = { a: 1, name: '张三', b: {} };
const obj3 = { a: 1, name: '张三', b: {} };
let obj4 = obj1;
console.log(obj1 === obj3);//false
console.log(obj1 === obj4);//true
2.使用JSON.stringfy()判断是否相等
JSON.stringfy()比较的是对象中的属性,不比较引用地址
const obj1 = { a: 1, name: '张三', b: { name: '1' } };
const obj3 = { a: 1, name: '张三', b: { name: '1' } };
let obj4 = obj1;
console.log(JSON.stringify(obj1) === JSON.stringify(obj3));//true
console.log(JSON.stringify(obj1) === JSON.stringify(obj4));//true
3.使用遍历属性判断是否相等
Object.keys()遍历属性对判断是否一致,for循环判断属性值是否一致
getAttribute(a: any, b: any) {
const obj1 = Object.keys(a);
const obj2 = Object.keys(b);
//属性不同则返回
if (obj1.length !== obj2.length) {
return false;
}
// 属性值不同
for (let key of obj1) {
if (a[key] !== b[key]) return false;
}
return true;
}
ngOnInit(): void {
//使用全等===判断是否相等
const obj1 = { a: 1, name: '张三', b: { name: '1' } };
const obj3 = { a: 1, name: '李四', b: { name: '1' } };
let obj4 = obj1;
console.log(this.getAttribute(obj1, obj3)); //false
console.log(this.getAttribute(obj1, obj4)); //true
}
七、防抖和节流
作用:都是在高频事件中防止函数被多次调用,以此优化性能
区别:1.防抖函数只会在高频事件结束后n毫秒调用一次函数
2.节流函数是在高频事件触发过程中每隔n毫秒调用一次函数
1.防抖
高频事件结束后n毫秒内只会调用一次函数,如果再次触发,则重新计算时间
//防抖(debounce)
//input框的输入、scroll事件滚动出发、按钮提交事件
//触发高频事件后n秒内函数只会执行一次,如果n秒内再次触发,则重新计算时间
debounceTime(func, timeout) {
let timer = null;
return function debounce() {
//清除定时器
clearTimeout(timer);
timer = setTimeout(() => {
//使得每次传入的函数的this都指向调用该debounceTime的调用者
func.apply(this, arguments);
}, timeout);
};
}
2.节流
持续触发事件后,保证每隔一段时间就执行一次事件
//节流(throttle)
//搜索联想、DOM 元素的拖拽功能实现
//频发触发事件,每隔一段时间执行一次函数,多次触发只会在间隔时间内执行一次
throttleTime(func, timeout) {
let timer = null;
return function throttle() {
//如果没有计时器 则执行
if (!timer) {
timer = setTimeout(() => {
func.apply(this, arguments);
//间隔时间结束 计时器清除 在规定的时间内只会触发一次
timer = null;
}, timeout);
}
};
}
八、ES6中Map和Set的区别和用法
1.Set
Set是一组key的集合,每个key都是唯一的不能重复所以可以用Set进行数组去重
//数组去重
const arr = [...new Set([1, 2, 3, 4, 4, 6, 7, 7])];
console.log(arr);//[1,2,3,4,6,7]
//Set的方法使用
//1.add() 添加元素
const newSet = new Set();
newSet.add('hello');
newSet.add('world');
newSet.add('!');
//2.delete() 删除元素
newSet.delete('!');
//3.has() 是否存在某个值
console.log(newSet.has('hello')); //true
//4.size Set中元素的数量
console.log(newSet.size); //2
//5.clear() 清除Set中所有元素
newSet.clear();
const set = new Set([1, 23, 4]);
//6.keys() Set中的所有元素的键名
console.log(set.keys()); //SetIterator {1, 23, 4}
//7.values() Set中所有元素的键值
console.log(set.values()); //SetIterator {1, 23, 4}
//8.entries() Set中所有键值对
console.log(set.entries()); //SetIterator {1 => 1, 23 => 23, 4 => 4}
2.Map
Map是一组键值对的结构,初始化Map需要一个二维数组,或者直接初始化一个空Map。
const map = new Map([
['name', 'zhangsan'],
['age', '18'],
['sex', 'male'],
]);
const newMap = new Map();
console.log(map); //Map(3) {'name' => 'zhangsan', 'age' => '18', 'sex' => 'male'}
//1.set(key,value) 新增
map.set('address', 'earth');
//2.get(key) 通过key查到对应的value
console.log(map.get('age')); //18
//3.has(key) 是否存在某个key
console.log(map.has('name')); //true
//4.delete(key) 删除某个key
map.delete('sex');
//5.clear() 清空Map里所有的键值对
map.clear();
newMap.set('data', 10);
newMap.set('total', 20);
//6.keys() 返回Map中所有的键
console.log(newMap.keys()); //MapIterator {'data', 'total'}
//7.values() 返回Map所有的键值
console.log(newMap.values()); //MapIterator {10, 20}
//8.entries() 返回Map中所有键值对
console.log(newMap.entries()); //MapIterator {'data' => 10, 'total' => 20}
//9.forEach() 遍历Map中所有键值对
newMap.forEach((value: any, key: any) => {
console.log(value, key);
//10 'data'
//20 'total'
});
九、数组去重的方式
1.使用Array.from()和Set()
const arr = [1, 5, 7, 2, 5, 7, 8, 8, null, null, undefined, undefined, NaN, NaN];
//Array.from从可迭代(Set Map)或类数组(存在length属性和索引元素的对象)对象创建数组
const newArr = Array.from(new Set(arr));
console.log(newArr);//[1, 5, 7, 2, 8, null, undefined, NaN]
2. 使用indexOf方法
indexOf无法区分NaN
const arr = [1, 5, 7, 2, 5, 7, 8, 8, null, null, undefined, undefined, NaN, NaN];
//无法区分NaN 因为NaN!==NaN NaN不等于本身
//利用数组的indexOf判断如果不存在则加入新数组
const newArr = [];
arr.forEach((item: any) => {
//判断新数组中是否存在某个值
if (newArr.indexOf(item) === -1) {
newArr.push(item);
}
});
console.log(newArr); //[1, 5, 7, 2, 8, null, undefined, NaN, NaN]
3.使用双层for循环+splice()
注意:undefined在数组中相当于数组空位即没有值,所以在使用数组方法filter、map、forEach时会直接跳过
以下例子中a[19],a[11],a[12],a[13]具有null或undefined值 索引不存在,所以无法使用for循环
const arr = [1, 5, 7, 2, 5, 7, 8, 8, null, null, NaN, NaN, undefined, undefined];
//使用两层循环+splice()
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
//去除序号较大的元素,数组长度-1,序号为j的被删除序号j后的元素顶上
arr.splice(j, 1);
arr.length--;
j--;
}
}
}
console.log(arr);//[1, 5, 7, 2, 8, null]
4.使用includes()方法
const arr = [1, 5, 7, 2, 5, 7, 8, 8, null, null, undefined, undefined, NaN, NaN];
//使用数组的includes()方法来检测是否存在某个值
const newArr = [];
arr.forEach((item: any) => {
//如果不存在数组中,则新增至数组
if (!newArr.includes(item)) {
newArr.push(item);
}
});
console.log(newArr);//[1, 5, 7, 2, 8, null, undefined, NaN]
5.使用Map去重
const arr = [1, 5, 7, 2, 5, 7, 8, 8, null, null, undefined, undefined, NaN, NaN];
//使用Map去重
const newArr = new Map();
arr.forEach((item: any) => {
//如果不存在数组中,则新增至数组
if (!newArr.has(item)) {
newArr.set(item, item);
}
});
const data = [...newArr.keys()];
console.log(data);// [1, 5, 7, 2, 8, null, undefined, NaN]
十、Promise函数相关知识点
1.promise状态
Promise状态有三种:pending(等待)、fulfilled(成功)、rejected(失败)
2.promise使用
注意:.catch()的作用是捕获Promise的错误,与then()的rejected回调作用几乎一致,catch()也能够捕获then()中抛出的错误
//成功状态
new Promise((resolve, reject) => {
resolve(2);
}).then(
resolved => {
console.log(resolved); //2
},
(error: any) => {
console.log(error);
}
);
//失败状态
new Promise((resolve, reject) => {
reject(444);
}).then(
resolved => {
console.log(resolved); //2
},
(error: any) => {
console.log(error);//444
}
);
//在.then中如果没有第二个失败的回调
//存在.catch(可以更清晰定义错误处理逻辑)会执行
new Promise((resolve, reject) => {
reject(444);
})
.then(
resolved => {
console.log(resolved); //2
}
// (error: any) => {
// console.log('rejected', error);
// }
)
.catch(error => {
console.log('catch', error);//444
});
3.多次调用.then
new Promise((resolve, reject) => { resolve(444); }) .then(value => { console.log(value); //2 return 888; }) .then(value => { //这里的值是上一个.then的返回值 console.log(value); //888 }) .then(value => { //上一个.then没有传值 则为undefined console.log(value); //undefined });
十一、去掉字符串内的空格
1.使用replace()
const str = ` a a a a `;
//replace方法返回一个新字符串,不会更改字符串
//全局匹配所有空格
const newStr = str.replace(/\s/g, '');
console.log(newStr); //aaaa
2.使用for循环
const str = ` a a a a `;
let newStr = '';
for (let i = 0; i < str.length; i++) {
if (str[i] !== ' ') {
newStr += str[i];
}
}
console.log(newStr);//aaaa
十二、??运算符
??的作用是用来判断一个变脸是否为null或者undefined,JavaScript两个问号运算符会检查一个变量的值是否为null或undefined。它只有在变量值为null或undefined时才会返回默认值,否则返回变量的实际值。
示例:
//只有当值为undefined/null时输出默认值??后的值,否则都输出??之前的值
let name = '';
console.log(name ?? 'hahah'); //输出空字符串
let key = undefined;
console.log(key ?? 'hahah'); //输出hahah
二、CSS知识点
一、CSS盒子模型
浏览器默认的盒子模型为box-sizing:content-box(默认)
CSS盒子模型包含标准盒子模型和IE盒子模型。
盒模型都是由四个部分组成的,分别是 margin、border、padding 和 content。
box-sizing: border-box; /*IE盒子模型*/
box-sizing: content-box; /*标准盒子模型*/
示例图:
//IE盒子模型
// 盒子的width和height分别为content、padding、border的宽高度相加
.box {
box-sizing: border-box;
width: 200px;
height: 200px;
border: 10px solid black;
margin: 10px;
padding: 10px;
background-color: aqua;
}
//W3c 标准盒子模型 盒子的width和height为content
.content {
box-sizing: content-box;
width: 200px;
height: 200px;
padding: 10px;
border: 10px solid black;
margin: 10px;
background-color: rgb(238, 185, 70);
}
二、CSS实现宽度自适应100%,宽高16:9的比例的矩形
假设宽度为100%,那么高度则为h= 9/16 = 56.25%
<div class="content">
<div class="box">这是一个16:9的盒子</div>
</div>
.content {
width: 50%;
.box {
width: 100%;
height: 0; /*防止矩形被里面的内容撑出多余的高度 且父元素未设置高度
此时如果使用百分比则是0的基础上设置 那么子元素也会没有高度 所以不能使用百分比*/
/*撑起盒子高度 如果为padding-top也会是16:9 但此时盒子内的内容则会在盒子下方*/
padding-bottom: 56.25%;
background: pink;
position: relative;
.box p {
width: 100%;
height: 100%;
position: absolute;
}
}
}
三、实现三角形
把需要隐藏的border设置为transparent即可
.content {
height: 0;
width: 0;
border-top: 100px solid pink;
/* border-bottom: 10px solid transparent; */
border-bottom: 100px solid yellow;
border-right: 100px solid greenyellow;
/* border-right: 10px solid transparent; */
border-left: 100px solid skyblue;
}
三、Angular知识点
四、面试问题
4.1 在项目中遇到过的难点
1.性能优化 如浏览器缓存问题、路由的懒加载问题、比如通过angular自带的debounceTime防抖来对一些搜索功能的api进行结合,减少调用的次数优化性能