就像我们人类为什么能生活在地球上一样,因为地球为我们提供了可以生存的条件,js运行在浏览器中,也是一样的,浏览器为js提供了运行的机制
浅分析js的运行机制:
1、当浏览器(它的内核/引擎)渲染和解析js的时候,会提供一个供js代码运行的环境,我们称这个环境为全局作用域(window global scope)
2、代码自上而下执行(之前还有一个变量提升阶段)
基本数据类型的存储机制:
基本数据类型的值会存储在当前作用域(栈内存)
var a=12; var b=a; b=13; console.log(a); //12 /*这里,先开辟一个空间储存12,
再声明了变量a,
然后让变量a和12相关联,
b=a的时候,是把12复制了一份赋值给b了,
这样做的目的是让 a的12,和b=a的12没有关系,
所以操作b=13的时候,改变的值不是同一个12
*/
1)首先会开辟一个空间存储12
2)在当前作用域中声明一个变量a
3)让声明的变量和存储的12进行关联(把12赋值给a,赋值的操作叫做定义)
基本数据类型(值类型),是按照值来操作的:把原有的值复制一份,放到新的空间或者位置上,和原来的值没有关系
引用数据类型的存储机制:
引用数据类型的值不能直接存储在当前作用域下,因为存储的内容过于复杂,先开辟一个新的空间(理解为仓库),把内容存储到这个空间中(堆内存)
var obj={ n:100, m:200 } /*有个空间存的 n:100,m:200 ,并且这个空间有个16进制的地址名称 AAAFFF111 把这个地址赋值给了obj obj=AAAFFF111地址(虚拟的地址) */ var obj1=obj;//声明了一个变量obj1,把obj存的地址给了obj1,两个变量存的是一个空间地址,相互之前会有影响 obj1.n=300; console.log(obj['n']);//300 相同地址的n被改变了
1)首先开辟一个新的内存空间,把对象中的键值对(函数存的是字符串)依次存储起来,为了保证后面可以找到这个空间,此空间有个16进制的地址
2)声明一个变量
3)让变量和空间地址关联在一起(把空间地址赋值给变量)
引用数据类型操作的是空间地址,把原来空间的地址赋值给新的变量,但是原来的空间没有被克隆,还是同一个空间,这样就会出现多个变量关联的相同的空间,相互之间就会存在影响了
栈内存 && 堆内存
栈内存:提供代码运行的环境,所有的基本数据类型都会在栈内存中开辟位置存储
堆内存:存储引用数据类型的值一个作用,对象存的是键值对,函数存储的是代码字符串
堆内存的释放:
1、放堆内存没有被任何变量或者其他东西占用,浏览器会在空闲的时候,自主的进行内存回收,把所有不被占用的堆内存销毁掉(谷歌浏览器的释放内存机制)
2、在创建内存的时候,在每个内存上贴一个标签(内存占用计数器),每被占用一次就记一次,不被占用了就减一次(IE浏览器的释放内存机制)
栈内存销毁:
一般情况下,当函数执行完成,所形成的私有作用域(栈内存)都会自动释放掉,特殊不销毁的情况:
1)函数执行完成,某些内容被内存以外的变量占用了
2)全局栈内存只有在页面关闭的时候才会释放掉
如果当前栈内存没有释放,之前存储的基本值也不会被释放,能够一直保存下来
堆内存销毁:
变量=null ;变量指向空对象指针,浏览器会在空闲的时候自主释放堆内存
总结:当js代码在浏览器中运行的时候,浏览器会开辟一个栈内存(全局作用域),基本数据类型的值会直接在栈内存中开辟空间,多个变量之间的值不会有关系,引用数据类型会开辟一个新的堆内存来储存,并分配一个16进制的地址,多个引用数据类型的变量可以存储同一个空间地址,可以相互更改同一个地址的内容,不管 是基本数据类型还是应用内数据类型,赋值操作都是先有值再有变量,再把值赋值给变量;
思考题:
var ary1=[1,2]; var ary2=ary1; ary2[0]=6;// 6,2 ary2=[3,4];//这里把ary2重新赋值了一个新的堆内存 ary2[1]=5;//3,5 ary1[1]=0;//6,0 console.log(ary1,ary2);//[6,0] [3,5]