2018-12-03 20:57:24javascript
内存泄漏指任何对象在您再也不拥有或须要他以后,其仍然存在内存中。html
也就是程序中分配的堆内存空间没有被及时释放或没法释放,致使的内存占用过多,形成程序运行速度减慢甚至卡顿、崩溃。前端
在浏览器中识别内存泄漏的方法:java
一段”高清“gif展现给你:面试
详见:【进阶1-4期】JavaScript深刻之带你走进内存机制数组
一共给本身出了三道题:浏览器
1. 基本类型值的拷贝:bash
1 var a = 1; 2 var b = a; 3 console.log(b); 4 b = 2; 5 console.log(a);
2. 引用类型值的拷贝:(浅拷贝)数据结构
1 var c = { 2 n: 1
3 } 4 var d = c; 5 d.n = 3; 6 console.log(c.n);
3. 基本类型值的拷贝:【经典】闭包
1 var e = { 2 n: 1
3 } 4 var f = e; 5 e.x = e = { n: 4}; 6 console.log(e.x); 7 console.log(f);
第一题打印:
> 1
> 1
首先第一个b弹出1,毫无疑问。能够理解成b = a = 1。
实际上他是执行:
var b; 给b建立一块空间
b = a;先查找a的值(1),再赋予给b变量。
而后第二个,依旧弹出1。
以前你理解b和a相等了,b变成2是否是a也要变成2啊?不是的,由于b和a不是一块空间。
通俗点理解,就像是拷贝了a的一个副本给b。此时咱们修改(副本)b的值,对a毫无影响。
因此尽管b为2了,a仍是1。
第二题打印:
> 3
刚看完上边说a和b不影响,再看这里是否是懵逼了。说好的不影响,怎么d.n改为了3,c.n也改为了3呢?
其实啊,这就是堆栈空间存值的不一样和拷贝堆内存数据的特色了:
首先要知道,堆栈空间存的值不一样:
var c = {}; 定义一个对象c。
js引擎要作的事情以下:
以后的代码,运行d.n = 3。就是把堆内存中惟一一处的那个{n:1}对象的n值给修改了。
此时,堆内存中{n:1}这个对象,如今变成了{n:3}。
第三题打印:
> undefined
> 一个对象:展开以下:
{ n: 1, x: { n:4 } }
此题是一个经典面试题,
首先第1-4行,和第二题定义c一个套路。
栈空间存了变量e和指针,堆空间存了对象{n:1};将e的指针再赋予f。
关键是第5行,这里若是你按从左向右顺序理解的话结果应该是:
各类可能
但这道题的坑点就在于js不是按照你想的、你阅读的顺序执行的。
首先,js中正确的赋值顺序是从右向左的。
也就是应该先从最后边开始,先将等号右边的赋值给等号左边。
但这道题还有坑点就是运算符的优先级:点比等号的优先级高。
也就是说,先执行的是
e.x = {n : 4}
而后执行:
e = { n: 4}
首先说先执行的代码执行后的结果
e.x被赋值后,至关于堆内存中,对象{n:1}多了一个属性x,而且值是{n : 4};
此时,e和f的值状况分别是这样的(注意下边的obj1和obj2分别是我本身为了区分对象给命名的)
而后,执行e = { n : 4}; 此时js引擎要作的事情就是:
开辟一个新的堆空间放新对象obj2 --> {n : 4}
而后将这个新对象的地址从新赋值给e。这一步能够这么理解:
var e = 'obj1的地址'; e = 'obj2的地址';
最终e在栈空间的值就是obj2的地址。
最后,执行console.log(f):
虽然e和obj1切断了关系,可是f还和obj1有关系。因此f打印出来的就是整个obj1。
这里e被从新指向obj2后,obj2里边并无x值,因此e.x是不存在的。
正常状况下,找不到一个变量会报错: 变量 is not defined。可是为何对象的属性值不存在时只是输出undefined呢?
这一点,咱们获取e.x会去对象身上找,若是不存在x,会去对象的原型链上找,一直找到最顶端,都找不到时就返回“undefined”
2018-12-05 21:14:46
观察下边的这段代码,进行一次引擎和做用域的对话:
1 function foo(a){ 2 var b = a; 3 return a + b; 4 } 5 var c = foo(2);
找出里边的几处RHS查询、几处LHS查询?分别是哪里?
答案:
背诵,具体文案见本周主题阅读第四条
垃圾回收器按期扫描对象,并计算引用了每一个对象的其余对象的数量。若是一个对象的引用数量为 0(没有其余对象引用过该对象),或对该对象的唯一引用是循环的,那么该对象的内存便可回收。
null也是js基本类型之一,它是一个字面量,特指对象的值未设置。表示缺乏的标识,指示变量未指向任何对象。
undefined也是js基本类型之一,是全局对象的一个属性。声明一个变量,未进行初始化时,这个变量的值就是undefiend,
给一个全局变量赋值null,至关于将这个变量的指针对象及值清空,若是是给对象的属性赋值null,或者局部变量赋值为null,至关于给这个属性分配一块空的内存空间,而后值是null。
js会回收全局变量为null的对象。
const foo = {};
// 为foo添加一个属性,能够成功
foo.prop = 123;
for.prop; // 获得123
// 将foo指向另外一个对象,报错:
foo = {};//TypeError: 'foo' is read-only
const实际上并非指变量的值不可改动,而是变量指向的那个内存地址所保存的数据不得改动。
对于简单类型的数据(string、number、boolean、null、undefined),值就保存在变量指向的那个内存地址,所以等同于常量
但对于引用类型的数据(复合类型的数据:对象、数组),变量指向的内存地址,保存的是一个指向堆内存实际数据的指针,const只能保证这个指针
是固定的(即指向的地址不变)。至于这个地址对应的堆内存中数据结构的变化,他是控制不了的。
所以,在上例中,为foo添加属性,实际上操做的是堆内存中foo对象的数据结构,const管不着,
而改变foo的指针,指向另外一个对象,const是不答应的。
(见本周阅读主题篇第六条)
setTimeout 的第一个参数使用字符串而非函数的话,会引起内存泄漏。
闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
学了堆栈内存空间,应该就理解了什么叫简单数据类型存在栈内存,复杂数据类型存在堆内存了。
而后面试中,常常会问、业务中也常常会遇到的问题就是深浅拷贝的问题了。
栈内存中简单数据类型直接拷贝就能获得一个副本,可是复杂数据类型的拷贝若是也想获得一个副本,就须要深拷贝了。
具体源码见文章《js中的浅拷贝和深拷贝》