每天背5道,务必背熟记住,希望能对找工作的小前端有点帮助
1、为什么 JavaScript 是单线程
JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
2、浅拷贝、深拷贝
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。基本类型不存在这个问题。
简单来说,有两个对象 A 和 B,B = A,当你修改 A的属性或者方法 时,B 的值也跟着发生了变化,这时候就叫浅拷贝。如果不发生变化,就叫深拷贝。在引用数据类型中,会产生浅拷贝的问题。
如何实现深拷贝?
(1)使用递归的方式实现深拷贝
(2)用**JSON.parse( JSON.stringify(obj) )**来完成深拷贝,但是该方法不能解决属性为函数,undefined,循环引用的的情况
(3)用Object.assign()来完成深拷贝,newObj = Object.assign({}, obj),这种方法对于一层对象来说是没有问题的,但是如果对象的属性对应的还是对象或者数组时,就是浅拷贝。
var obj = { a: {a: "kobe", b: 39} };
var initalObj = Object.assign({}, obj);
initalObj.a.a = "wade";
console.log(obj.a.a); // wade 原对象也改变了,是浅拷贝
一层的情况
let obj = {
username: 'kobe'
};
let obj2 = Object.assign({},obj);
obj2.username = 'wade';
console.log(obj);//{username: "kobe"} 原对象没有被改变,是深拷贝
3、数组去重
方法1:定义一个新数组,并存放原数组的第一个元素,然后将元素组一一和新数组的元素对比,若不同则存放在新数组中
方法2:先将原数组排序,在与相邻的进行比较,如果不同则存入新数组。
方法3:利用对象属性存在的特性,如果没有该属性则存入新数组。
Array.prototype.unique = function () {
var arr = this, obj = {}, result = [];
for (var i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) { //如果能查找到,证明数组元素重复了
obj[arr[i]] = 1;
result.push(arr[i]);
}
}
return result;
};
var a = [1, 2, 3, 1, 2, 3];
var b = a.unique();
console.log(b); //打印结果:(3) [1, 2, 3]
方法4(最常用):使用es6 set,Set数据结构,它类似于数组,其成员的值都是唯一的
let arr= [1, 2, 3, 3, 5, 7, 2, 6, 8];
console.log([...new Set(arr)]);
方法5:使用filter过滤函数去重。
var arr = [1, 2, 3, 1, 2, 3];
console.log(arr.filter((v, i, arr) => arr.indexOf(v) === i))//打印结果:(3) [1, 2, 3]
4、防抖、节流
防抖:触发高频函数事件后,n秒内函数只能执行一次,如果在n秒内这个事件再次被触发的话,那么会重新计算时间。通常使用的场景是:用户输入,只需再输入完成后做一次输入校验即可。
节流:所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。通常使用场景: 滚动条事件 或者 resize 事件,通常每隔 100~500 ms执行一次即可
//防抖
function debounce(func, wait){
let timeout;
return function(){
if(timeout){
clearTimeout(timeout)
}
timeout = setTimeout(() => {
func.apply(this, arguments)
}, wait)
}}
//节流
function throttle(func, wait){
let timeout;
return function(){
if(!timeout){
timeout = setTimeout(() => {
timeout = null;
func.apply(this, arguments)
}, wait)
}
}}
5、数组操作
-
map【常用】: 遍历数组,返回回调返回值组成的新数组 -
forEach【常用】: 无法break,可以用try/catch中throw new Error来停止 -
filter【常用】: 过滤 -
some: 有一项返回true,则整体为true -
every: 有一项返回false,则整体为false -
join【常用】: 通过指定连接符生成字符串 -
push / pop: 末尾推入和弹出,改变原数组,push返回数组长度,pop返回原数组最后一项; -
unshift / shift: 头部推入和弹出,改变原数组,unshift返回数组长度,shift返回原数组第一项 ; -
sort(fn) / reverse【常用】: 排序与反转,改变原数组 -
concat【常用】: 连接数组,不影响原数组, 浅拷贝 -
slice(start, end): 返回截断后的新数组,不改变原数组 -
splice(start, number, value...)【常用】: 返回删除元素组成的数组,value 为插入项,改变原数组 -
indexOf / lastIndexOf(value, fromIndex): 查找数组项,返回对应的下标 -
reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur 为当前值-
当传入
defaultPrev时,从第一项开始; -
当未传入时,则为第二项
-
本着能为找工作中的前端帮一点小忙的初衷,借鉴了掘金里面很多大佬的文章,如有侵权请告知