赞助我以写出更好的文章,give me a cup of coffee?javascript
基本类型值有:undefined,NUll,Boolean,Number和String
,这些类型分别在内存中占有固定的大小空间,他们的值保存在栈空间,咱们经过按值来访问的。前端
(1)值类型:数值、布尔值、null、undefined。 (2)引用类型:对象、数组、函数。
若是赋值的是引用类型的值,则必须在堆内存中为这个值分配空间。因为这种值的大小不固定(对象有不少属性和方法),所以不能把他们保存到栈内存中。但内存地址大小是固定的,所以能够将内存地址保存在栈内存中。java
<script type="text/javascript”> var box = new Object(); //建立一个引用类型 var box = "trigkit4"; //基本类型值是字符串 box.age = 21; //基本类型值添加属性很怪异,由于只有对象才能够添加属性。 alert(box.age); //不是引用类型,没法输出; </script>
简而言之,堆内存存放引用值,栈内存存放固定类型值。“引用”是一个指向对象实际位置的指针。git
在这里需注意的是,引用指向的是具体的对象,而不是另外一个引用。github
这里的对象能够是字符串对象,数字对象,数组对象等web
<script type="text/javascript"> var man = new Object();//man指向了栈内存的空间地址 man.name = "Jack"; var man2 = man;//man2得到了man的指向地址 alert(man2.name);//两个都弹出Jack alert(man.name); </script>
再看下面这个例子:面试
<script type="text/javascript"> var man = new Object();//man指向了栈内存的空间地址 man.name = "Jack"; var man2 = man;//man2得到了man的指向地址 man2.name = "ming";//由于他们都指向同一个object,同一个name,无论修改谁,你们都修改了 alert(man2.name);//两个都弹出ming alert(man.name); </script>
由以上能够得出:在变量复制方面,基本类型和引用类型也有所不一样,基本类型复制的是值自己,而引用类型复制的是地址。segmentfault
ECMAScript中,全部函数的参数都是按值传递的,数组
<script type="text/javascript"> function box(num){ //按值传递 num+=10; return num; } var num = 10; var result = box(num); alert(result); //若是是按引用传递,那么函数里的num会成为相似全局变量,把外面的number替换掉 alert(num); //也就是说,最后应该输出20(这里输出10) </script>
js
没有按引用传递的,若是存在引用传递的话,那么函数内的变量将是全局变量,在外部也能够访问。但这明显是不可能的。浏览器
执行环境是javascript
中最为重要的概念之一,执行环境定义了变量或函数有权访问其余数据。
全局执行环境是最外围的执行环境,在web浏览器中,全局执行环境是window
对象,所以,全部的全局变量的函数都是做为window
的属性和方法建立的。
<script type="text/javascript"> var name = "Jack"; //定义全局变量 function setName(){ return "trigkit4"; } alert(window.name); //全局变量,最外围,属于window属性 alert(window.setName()); //全局函数,最外围,属于window方法 </script>
当执行环境内的代码执行完毕后,该环境被销毁,保存其中的变量和函数也随之销毁,若是是全局环境,需全部程序执行完毕或网页完毕后才会销毁。
<script type="text/javascript"> var name = "Jack"; function setName(){ name = "trigkit4"; //去掉var变成了全局变量 } setName(); alert(name);//弹出trigkit4 </script>
<script type="text/javascript"> var name = "Jack"; function setName(name){ //经过传参,也是局部变量 alert(name); } setName("trigkit4");//弹出trigkit4 alert(name);//弹出Jack </script>
函数体内还包含函数,只有这个函数才能够访问内一层的函数
<script type="text/javascript"> var name = "Jack"; function setName(){ function setYear(){ //setYear()方法的做用域在setName()内 return 21; } } alert(setYear());//没法访问,出错 </script>
能够经过以下方法进行访问:
<script type="text/javascript"> var name = "Jack"; function setName(){ function setYear(){ //setYear()方法的做用域在setName()内 return 21; } return setYear(); } alert(setName()); //弹出21 </script>
再一个做用域例子:
<script type="text/javascript"> var name = "Jack"; function setName(){ function setYear(){ //setYear()方法的做用域在setName()内 var b = "hi"; //变量b的做用域在setYear()内 return 21; } alert(b);//没法访问 } </script>
当代码在一个环境中执行的时候,就会造成一种叫作做用域链
的东西,它的用途是保证对执行环境中有访问权限的变量和函数进行有序访问(指按照规则层次来访问),做用域链的前端,就是执行环境的变量对象。
变量没有在函数内声明或者声明的时候没有带var
就是全局变量,拥有全局做用域,window
对象的全部属性拥有全局做用域;在代码任何地方均可以访问,函数内部声明而且以var
修饰的变量就是局部变量,只能在函数体内使用,函数的参数虽然没有使用var
但仍然是局部变量。
// if语句: <script type="text/javascript"> if(true){ //if语句的花括号没有做用域的功能。 var box = "trigkit4"; } alert(box);//弹出 trigkit4 </script>
for循环语句也是如此。
在变量的查询中,访问局部变量要比全局变量来得快,所以不须要向上搜索做用域链。
以下例子:
<script type="text/javascript"> var name = "Jack"; function setName(){ var name = "trigkit4"; return name; //从底层向上搜索变量 } alert(setName()); </script>
每一个环境均可以向上搜索做用域链,以查询变量和函数名;但任何环境都不能经过向下搜索做用域链而进入另外一个执行环境。在这里,若是去掉var name = "trigkit4"
,那么将弹出“Jack”
javascript
具备自动垃圾回收机制,一旦数据再也不使用,能够将其设为"null"来释放引用
一个很简单的例子:一个DOM对象被一个Javascript
对象引用,与此同时又引用同一个或其它的Javascript
对象,这个DOM
对象可能会引起内存泄露。这个DOM
对象的引用将不会在脚本中止的时候被垃圾回收器回收。要想破坏循环引用,引用DOM
元素的对象或DOM
对象的引用须要被赋值为null
。
在闭包中引入闭包外部的变量时,当闭包结束时此对象没法被垃圾回收(GC)。
var a = function() { var largeStr = new Array(1000000).join('x'); return function() { return largeStr; } }();
当原有的COM被移除时,子结点引用没有被移除则没法回收。
var select = document.querySelector; var treeRef = select('#tree'); //在COM树中leafRef是treeFre的一个子结点 var leafRef = select('#leaf'); var body = select('body'); body.removeChild(treeRef); //#tree不能被回收入,由于treeRef还在 //解决方法: treeRef = null; //tree还不能被回收,由于叶子结果leafRef还在 leafRef = null; //如今#tree能够被释放了。
定时器也是常见产生内存泄露的地方:
for (var i = 0; i < 90000; i++) { var buggyObject = { callAgain: function() { var ref = this; var val = setTimeout(function() { ref.callAgain(); }, 90000); } } buggyObject.callAgain(); //虽然你想回收可是timer还在 buggyObject = null; }
Chrome
自带的内存调试工具能够很方便地查看内存使用状况和内存泄露:
在 Timeline -> Memory 点击record便可:
相关文章:
咱们能够利用闭包来突破做用域链,详解js闭包