1、Event Loop(事件循环)机制
JS是单线程的非阻塞语言
为什么是单线程(如果js是多线程,那么两个线程同时对同一个Dom进行操作,一个增一个删,浏览器该如何执行?)
非阻塞(当代码需要执行一个异步操作,该操作不会立刻返回结果,主线程会挂起这个任务,再异步任务返回结果后再执行相应的回调)
2、原型链
每个函数都有一个属性prototype,这就是原型对象;如果我们拿这个函数通过new构造函数可以创建一个实例对象,这个实例对象自身会有一个指针(proto)指向它的构造函数的原型对象,这样再构造函数和实例对象之间就建立起了连接
使用原型链的作用
- 避免代码冗余,公共的属性和方法可以放到原型对象中
- 减少内存占用
- 继承
- propt (实例对象指向原型对象的指针,隐式原型,每个对象都有的属性)
- prototype(构造函数的原型对象,显士原型,函数独有)
3、操作数组的方法
索引 | 方法名 | 功能 | 改变原数组 | 返回内容 | 用法 |
---|---|---|---|---|---|
1 | push() | 在尾部添加元素 | 会 | 返回数组的长度 | |
2 | unshift() | 在头部添加元素 | 会 | 返回数组的长度 | |
3 | pop() | 在尾部删除元素 | 会 | 返回删除的元素 | |
4 | shift() | 在头部删除元素 | 会 | 返回删除的元素 | |
5 | slice() | 提取数组的一部分 | 不会 | 提取的新数组 | slice(开始位置,结束位置)提取内容不包含结束位置 |
6 | splice() | 删除数组的一部分 | 会 | 返回删除的元素 | splice(开始位置,删除个数,插入元素) |
7 | reverse() | 逆转放置元素位置 | 会 | 返回逆转放置的数组 | |
8 | sort() | 排序 | 会 | 返回排序后的数组 | arr.sort((a,b)=>{ return a.key-b.key}) |
9 | join() | 将所有元素放入字符串 | 字符串 | arr.join(‘/’) 什么都不加,用逗号分隔;只有引号是空白; | |
10 | for…in | 遍历数组 | 更适合遍历对象,不建议遍历数组for( let value in arr){console.log(value, arr[value])} | ||
11 | concat() | 连接两个数组 | 不会 | ||
12 | forEach() | 遍历 | 本身不会,如果修改了属性则会(可对数组进行深拷贝) | 无返回值 | arr.forEach((元素,索引,当前数组)=> {}) |
13 | map() | 遍历: | 本身不会,如果修改了属性则会(可对数组进行深拷贝) | 会返回新数组(需要加return否则是undefined) | 不会对空数组进行检测arr.map((元素,索引,当前数组)=> {}) |
14 | filter() | 按条件过滤 | 不会 | 新数组(满足条件项) | arr.filter((value,index,arr)=>{return value>0}) |
15 | some() | 查找 | 不会 | boolean | 如果所有元素都满足判断条件,则返回true,若所有元素都不满足判断条件,则返回falsearr.some(value=> value < 0) |
16 | every() | 查找 | 不会 | boolean | 此方法是将所有元素进行判断返回一个布尔值,如果所有元素都满足判断条件,则返回true,否则为falsearr.every((value,index,arr)=>{return value>0}) |
17 | indexOf() | 查找 | 不会 | 返回数组中某个指定的元素位置 | Array.indexOf(item,start)[NaN].indexOf(NaN) // -1 |
18 | includes | 查找 | 不会 | 返回一个Boolean | [1, 2, 3].includes(2) //true; 返回布尔值,比indexOf更直观,对于NaN校验更准确 |
19 | lastIndexOf() | 查找 | 不会 | 可返回一个指定的元素在数组中最后出现的位置 | Array.lastIndexOf(item,start) |
20 | fill()(ES6) | 用一个固定值填充 | 会 | 返回新数组 | arr.fill(value, start, end)start–默认0;end–默认length |
21 | find (ES6) | 查找 | 不会 | 返回满足条件的第一项(return) | arr.find((value, index, arr)=> return value>0){} //两个参数,第二个为回调let param = [‘’].find((item)=>{// 同时检测多个字符串是否在当前内容中 return item==‘2’ |
22 | findIndex(ES6) | 查找 | 不会 | 返回满足条件的第一项的索引(return) | arr.find((value, index, arr)=> return value>0){}//两个参数,第二个为回调 |
23 | reduce | (return) | numbers.reduce((preValue,currentValue)=>{return preValue + currentValue})//数组求和 |
4、数组遍历方法性能比较
- 方法:通过一个时间函数,执行对应方法n次,计算时长
- 结果:for循环遍历 < for…of遍历 < forEach遍历 < for…in遍历 < map遍历
5、深拷贝的方法
- for 循环实现 ( for + push )
- slice 方法 ( arr.slice(0) )
- concat 方法 ( arr.concat() )
- Es6的 … 扩展运算符 ( var […arrNew] = arr )
- JSON.stringify() 和 JSON.parse() (适用于对象的深拷贝,对象转为字符串后赋值给另一个变量)
6、数组去重的方法
- for + for
- for + indexOf
- Set (Es6)
let arrList = [1,2,4,6,2,7,2]
let arrListNew = Array.from(new Set(arrList))
console.log(arrList)//[1, 2, 4, 6, 7]
- filter + indexOf
let arrList = [1,2,4,5,2,1]
let arrNew = arrList.filter((item,index,arr)=>{ return arr.indexOf(item)==index;})
console.log(arrNew)
7、检验数组的方法(typeOf、instanceOf)
- typeOf ( 返回一个字符串,如果检测数组返回 ‘object’ )
- instanceof ( 返回一个布尔值,arr instanceof Array )
- es5的 isArray (Array.isArray(arr))
- 验证对象的构造函数 ( arr.constructor === Array )
- 检测对象的原型 ( Object.prototype.toString.call(arr)‘[object Array]’ )
8、数字精度处理(tiFixed、Number)
- 简单的四舍五入*((0.1+0.2).toFixed(1);//0.3)有弊端:(2.445).toFixed(2)* IE显示2.45,但是chrome显示2.44
- Math.round() 函数返回一个数字四舍五入后最接近的整数,但 2.445 * 100=244.49999999999997,不是244.5,Math.round(2.445 * 100) // 244
- 先toPrecision取固定位数,parseFloat()解析字符串并返回浮点数
- bigInt()
let test = '9999999999999999';
let num = BigInt(test)
console.log(num);//9999999999999999n
console.log(String(num));//9999999999999999
9、This指向问题
- this出现在全局函数中,指向window
- this出现在严格模式中,永远不会指向window
- 当某个函数为对象的某个属性时,在这个函数内部this指向这个对象
- this出现在构造函数中,指向构造函数新创建的对象
- 当一个函数被绑定事件处理函数时,this指向被点击的这个元素
- this出现在箭头函数中时,this和父级作用域的this指向相同
- 修改this的指向:
– 使用call、apply、bind修改this指向
– 使用new关键字改变this指向
10、节流和防抖(针对相应跟不上触发频率这类问题)
- 节流:设置一个定时器,在固定时间段内多次点击只会执行一次
//
- 防抖:在固定时间段连续点击,会清除掉上次点击的定时器重新计时,最终只会执行最后一次的点击
const debounce = (function(){//防抖函数
let time = null;
return function(fn, sec){
clearTimeout(time);
time = setTimeout(fn, sec)
}
})()
// 滚动事件
window.addEventListener('scroll', ()=>{
debounce(()=>{
console.log(Math.random());
})
});
<!--
* @description:
* 功能:首次点击立即执行;n次点击判断与上次点击的间隔,
* 如果大于指定时间,则立即执行,否则延迟执行。
!-->
fangdou() {
let num = Math.random();
this.times = new Date().getTime();
this.list.push(num);
if (!this.times_old) {
this.listAll.push(num);
console.log(this.list);
this.times_old = this.times;
this.list = [];
} else {
let res = this.times - this.times_old;
if (res > 1000) {
this.listAll.push(this.list[this.list.length - 1]);
console.log(this.list);
if (this.timer) {
clearTimeout(this.timer);
}
this.times_old = this.times;
this.list = [];
} else {
if (this.timer) {
clearTimeout(this.timer);
}
this.timer = setTimeout(() => {
this.listAll.push(num);
console.log(this.list);
this.times_old = this.times;
this.list = [];
}, 1000 - res);
}
}
},
11、垃圾回收机制
- 垃圾指什么:指的是一些不再使用的内存;
- 回收指什么:针对不再使用的内存,需要进行释放,以便再次使用;
- 什么是垃圾回收:在JS中有一套自动的回收机制,通过一些回收算法,找出不再使用的引用的变量或者属性,由JS引擎按照固定周期释放其所占内存;
- 常见的算法策略:
- 引用计数算法
- 思路:记录每个变量使用次数,当被引用时标记 +1,当被其它值覆盖引用标记 -1,变为0时被垃圾回收器收回;
- 优点:引用计数为0时,发现垃圾立即回收;最大限度减少程序暂停;
- 缺点:无法回收循环引用的对象;控件开销比较大;
- 标记清除算法
- 思路:垃圾回收器在运行时会假设所有对象都是垃圾,全部标记为0;然后从根对象开始遍历,把不是垃圾的标记为1;清除掉所有标记为0的垃圾,回收其内存;然后把所有节点都改为0,等待下一次回收;
- 优点:实现简单;能够回收循环引用的对象;是V8引擎使用最多的算法;
- 缺点:在清除对象后剩余对象的内存的位置不变,出现一些内存碎片,需要重新分配;
- 标记整理算法
- 在标记结束后将不需要清理的对象向一侧移动,最后清理边界的内存
- 分代回收算法
- V8引擎主要使用标记清除算法和分代回收算法;
- 引用计数算法
- 自动回收什么时候执行:全局变量在关闭页面才会回收,局部变量在调用函数完之后就会回收;
- 针对闭包:可以通过将内部变量置空null来释放内存;
12、闭包
–
13、bind、apply、call
–