动画:《大前端吊打面试官系列》 之原生 JavaScript 精华篇( 七 )


最常见的就是在 IE BOM 和 DOM 中,使用的对象并不是 js 对象,所以垃圾回收是基于计数策略的 。但是在 IE9 已经将 BOM 和 DOM 真正的转化为了 js 对象,所以循环引用的问题得到解决 。
如何管理内存
虽然说是 js 的内存都是自动管理的,但是对于 js 还是存在一些问题的,最主要的一个问题就是分配给 Web 浏览器的可用内存数量通常比分配给桌面应用程序的少 。
为了能够让页面获得最好的性能,必须确保 js 变量占用最少的内存,最好的方式就是将不用的变量引用释放掉,也叫做解除引用 。
var a = 20;// 在堆内存中给数值变量分配空间alert(a + 100);// 使用内存var a = null; // 使用完毕之后,释放内存空间
补充:因为通过上边的垃圾回收机制的标记清除法的原理得知,只有与环境变量失去引用的变量才会被标记回收,所用上述例子通过将对象的引用设置为 null ,此变量也就失去了引用,等待被垃圾回收器回收 。
深拷贝和浅拷贝
面试官:什么是深拷贝?什么是浅拷贝?
上边在基本类型中我们说到,数据类型分为基本类型和引用类型 。对基本类型的拷贝就是对值复制进行一次拷贝,而对于引用类型来说,拷贝的不是值,而是值的地址,最终两个变量的地址指向的是同一个值 。还是以前的例子:
var a = 10;var b = a;b = 30;console.log(a); // 10值console.log(b); // 30值var obj1 = new Object();var obj2 = obj1;obj2.name = "小鹿";console.log(obj1.name); // 小鹿
要想将 obj1 和 obj2 的关系断开,也就是不让他指向同一个地址 。根据不同层次的拷贝,分为深拷贝和浅拷贝 。
面试官:浅拷贝和深拷贝分别如何实现的?有哪几种实现方式?
// 实现浅克隆function shallowClone(o){const obj = {};for(let i in o){obj[i] = o[i]}return obj;}
let a = {c: 1}let b = {...a}a.c = 2console.log(b.c) // 1
let a = {c: 1}let b = Object.assign({}, a)a.c = 2console.log(b.c) // 1
对于深拷贝来说,在浅拷贝的基础上加上递归,我们改动上边自己实现的浅拷贝代码:
var a1 = {b: {c: {d: 1}};function clone(source) {var target = {};for(var i in source) {if (source.hasOwnProperty(i)) {if (typeof source[i] === 'object') {target[i] = clone(source[i]); // 递归} else {target[i] = source[i];}}}return target;}
如果功底稍微扎实的小伙伴可以看出上边深拷贝存在的问题:
var a = {};a.a = a;clone(a); // 会造成一个死循环
两种解决循环引用问题的办法:
还有一个最简单的实现深拷贝的方式,那就是利用 JSON.parse(JSON.()),但是也存在一定的局限性 。
function cloneJSON(source) {return JSON.parse(JSON.stringify(source));}
对于这种方法来说,内部的原理实现也是使用的递归,递归到一定深度,也会出现爆栈问题 。但是对于循环引用的问题不会出现,内部的解决方案正是用到了循环检测 。对于详细的实现一个深拷贝,具体参考文章:[深拷贝的终极探索]()
异步编程
由于是单线程的,单线程就意味着阻塞问题,当一个任务执行完成之后才能执行下一个任务 。这样就会导致出现页面卡死的状态,页面无响应,影响用户的体验,所以不得不出现了同步和异步的解决方案 。