前端面试基础整理(一)
函数节流
在规定时间内只允许触发一次。
应用场景:防暴击或者没必要的频繁调用(一般多用在某些鼠标事情)
应用目的:节约计算资源
方法:可根据时间戳或定时器实现
// 时间戳方案 function throttle(fn, wait) { var pre = Date.now(); return function() { var context = this; var args = arguments; console.log("args", arguments); var now = Date.now(); if (now - pre >= wait) { fn.apply(context, args); pre = Date.now(); } }; } // 定时器方案 // function throttle(fn, wait) { // var timer = null; // return function() { // var context = this; // var args = arguments; // if (!timer) { // timer = setTimeout(function() { // fn.apply(context, args); // timer = null; // }, wait); // } // }; // } function handle() { console.log(Math.random()); } window.addEventListener("mousemove", throttle(handle, 1000));
new对象实际进行的步骤
创建一个空的新对象 var obj = new Object()
让空对象的原型属性_proto_指向原型链prototype上: obj._proto_ = Func.prototype
让构造函数this指向obj,并执行函数体 var result = Func.call(obj)
判断返回类型,如果是值就返回这个obj,如果是引用类型,就返回这个引用对象
深拷贝与浅拷贝
深浅相对拷贝层级而言
基本类型的名值都存放在栈内,故当b拷贝a后,a的值发生改变,并不影响b的值
let a = 1; let b = a; a = 2 console.log(b) // 1
而引用类型(obj,包括无序名值对{a, 1}, 有序名值对[1,2,3]以及函数),名跟地址存放在栈内,而值存放在堆中,故
let a = { age: 1 } let b = a // b复制的是a的地址, a.age = 2 console.log(b.age) // 2 a、b地址相同,指向同一个值,故当a变化时,b对应的属性值也发生改变
为了让b的值不随a的值变化,这种层级不多的,可用浅拷贝实现
// 方法一: Object.assign let a = { age: 1 } let b = Object.assign({}, a) a.age = 2 console.log(b.age) // 1 // 方法二: …扩展运算符 let a = { age: 1 } let b = { ...a } a.age = 2 console.log(b.age) // 1
但当a的层级较多时,上述方法在第二层级就无效了
let a = { age: 1, jobs: { first: 'FE' } } let b = { ...a } a.jobs.first = 'native' console.log(b.jobs.first) // native
故此时需要用到深拷贝 JSON.parse(JSON.stringify(obj))
let a = { age: 1, jobs: { first: 'FE' } } let b = JSON.parse(JSON.stringify(a)) a.jobs.first = 'native' console.log(b.jobs.first) // FE
但该方法不足之处有:
- 不能解决内部循环使用的问题
- 会忽略Symbol跟undifined类型对应的属性
- 不能序列化函数(会忽略函数类型)