js常见的问题(闭包、原型、防抖、拷贝)
1、闭包
定义:函数 A 返回了一个函数 B,并且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。
闭包的特性:
1)函数嵌套
2)内部函数引用外部函数变量
3)变量和参数不会被垃圾回收机制回收
闭包的缺点:
常驻内存,会增大内存使用量,使用不当很容易造成内存泄露
闭包的优点:
1)避免全局变量的污染
2)希望常驻内存(常用场景:函数中使用定时器)
2、原型和原型链
原型对象:
在 JavaScript 中,每当定义一个对象(函数也是对象)时候,对象中都会包含一些预定义的属性;
其中每个函数对象都有一个prototype 属性,这个属性指向函数的原型对象。
原型:
在JavaScript中,每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个
prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。
原型链:
原型链是由原型对象组成的;
每个对象都有 __proto__ 属性,指向了创建该对象的构造函数的原型,__proto__ 将对象连接起来组成了原型链。
是一个用来实现继承和共享属性的有限的对象链。
注意:
prototype是函数的一个属性(每个函数都有一个prototype属性),这个属性是一个指针,指向一个对象。它是显示修改对象的原型的属性。
__proto__是一个对象拥有的内置属性(请注意:prototype是函数的内置属性,__proto__是对象的内置属性),是JS内部使用寻找原型链的属性。
3、防抖和节流
防抖和节流的作用都是防止函数多次调用。
区别在于,假设一个用户一直触发这个函数,且每次触发函数的间隔小于wait,防抖的情况下只会调用一次,而节流的 情况会每隔一定时间(参数wait)调用函数。
在日常开发中表现为:
节流:在滚动事件中需要做个复杂计算
防抖:按钮的防二次点击操作
/** * @desc 函数防抖 * @param func 目标函数 * @param wait 延迟执行毫秒数 * @param immediate true - 立即执行, false - 延迟执行 * @param 三个参数,第二,三个参数可以省略,默认为1000,false */ function debounce(func, wait, immediate) { let timer; wait = wait || 1000; return function () { let context = this, args = arguments; if (timer) clearTimeout(timer); if (immediate) { let callNow = !timer; timer = setTimeout(() => { timer = null; }, wait); if (callNow) func.apply(context, args); } else { timer = setTimeout(() => { func.apply(context, args); }, wait); } }; }
/** * @function throttle 函数节流 * @param {Function} fn 需要节流的函数 * @param {Number} interval 间隔时间 * @return {Function} 经过节流处理的函数 * */ function throttle(fn, interval) { let timer = null; // 定时器 let firstTime = true; // 判断是否是第一次执行 // 利用闭包 return function () { // 拿到函数的参数数组 let args = Array.prototype.slice.call(arguments, 0); // 拿到当前的函数作用域 let _this = this; // 如果是第一次执行的话,需要立即执行该函数 if (firstTime) { // 通过apply,绑定当前函数的作用域以及传递参数 fn.apply(_this, args); // 修改标识为null,释放内存 firstTime = null; } // 如果当前有正在等待执行的函数则直接返回 if (timer) return; // 开启一个倒计时定时器 timer = setTimeout(function () { // 通过apply,绑定当前函数的作用域以及传递参数 fn.apply(_this, args); // 清除之前的定时器 timer = null; // 默认300ms执行一次 }, interval || 300); }; }
4、深拷贝和浅拷贝
深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。
1)深拷贝
深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。
2)浅拷贝
浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化
实现对象的深拷贝:
1)递归实现
2)JSON.parse(JSON.stringify(obj))
5、异步
js的异步和其它语言的异步是不相同的,本质上还是同步;因为浏览器会有一个Event Queue存放异步通知,js执行代码时会产生一个执行栈,同步的代码在执行栈中,异步的在Event Queue中;
只有当执行栈为空时,就是才会去Event Queue中查看是否有需要处理的通知,有的话拿到执行栈中去执行。
浙公网安备 33010602011771号