JavaScript 变量、作用域及内存详解
基本类型值有:undefined,NUll,Boolean,Number和String
,这些类型分别在内存中占有固定的大小空间,他们的值保存在栈空间,我们通过按值来访问的。
(1)值类型:数值、布尔值、null、undefined。
(2)引用类型:对象、数组、函数。
如果赋值的是引用类型的值,则必须在堆内存中为这个值分配空间。由于这种值的大小不固定(对象有很多属性和方法),因此不能把他们保存到栈内存中。但内存地址大小是固定的,因此可以将内存地址保存在栈内存中。
<script type="text/javascript”> var box = new Object(); //创建一个引用类型 var box = "trigkit4"; //基本类型值是字符串 box.age = 21; //基本类型值添加属性很怪异,因为只有对象才可以添加属性。 alert(box.age); //不是引用类型,无法输出; </script>
简而言之,堆内存存放引用值,栈内存存放固定类型值。“引用”是一个指向对象实际位置的指针。
在这里需注意的是,引用指向的是具体的对象,而不是另一个引用。
这里的对象可以是字符串对象,数字对象,数组对象等
<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>
由以上可以得出:在变量复制方面,基本类型和引用类型也有所不同,基本类型复制的是值本身,而引用类型复制的是地址。
传递参数
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>
当执行环境内的代码执行完毕后,该环境被销毁,保存其中的变量和函数也随之销毁,如果是全局环境,需所有程序执行完毕或网页完毕后才会销毁。
去掉var的局部变量
<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; } }();
DOM泄露
当原有的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可以被释放了。
Timers计(定)时器泄露
定时器也是常见产生内存泄露的地方:
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即可。
JavaScript 变量、作用域及内存详解的更多相关文章
- 第一百零六节,JavaScript变量作用域及内存
JavaScript变量作用域及内存 学习要点: 1.变量及作用域 2.内存问题 JavaScript的变量与其他语言的变量有很大区别.JavaScript变量是松散型的(不强制类型)本质,决定了它只 ...
- JavaScript之作用域与闭包详解
前言: JavaScript是一种应用非常广泛的语言,其也有一些自身特点和优势,本文重在讲述其作用域机制以及闭包,会从一些实例来探讨其机理. 作用域在JavaScript程序员日常使用中有不同的含义, ...
- PHP如何释放内存之unset销毁变量并释放内存详解
PHP的unset()函数用来清除.销毁变量,不用的变量,我们可以用unset()将它销毁.但是某些时候,用unset()却无法达到销毁变量占用的内存!我们先看一个例子: <?php $s = ...
- JavaScript变量作用域和内存问题(二)
执行环境是js中特别重要的概念,是指变量或者函数可以访问其他数据,定义自己的行为.每个执行环境都有一个与之相对应的变量对象,执行环境中定义的所有变量和函数都保存在这个变量中,我们看不到这个变量,但是后 ...
- JavaScript 内存详解 & 分析指南
前言 JavaScript 诞生于 1995 年,最初被设计用于网页内的表单验证. 这些年来 JavaScript 成长飞速,生态圈日益壮大,成为了最受程序员欢迎的开发语言之一.并且现在的 JavaS ...
- Java中堆内存和栈内存详解2
Java中堆内存和栈内存详解 Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...
- 高性能JavaScript模板引擎实现原理详解
这篇文章主要介绍了JavaScript模板引擎实现原理详解,本文着重讲解artTemplate模板的实现原理,它采用预编译方式让性能有了质的飞跃,是其它知名模板引擎的25.32 倍,需要的朋友可以参考 ...
- 【转】javascript变量作用域、匿名函数及闭包
下面这段话为摘抄,看到网上大多数人使用的是变量在使用的时候声明而不是在顶端声明,也可能考虑到js查找变量影响性能的问题,哪里用就在哪里声明,也很好. 在Javascript中,我们在写函数的时候往往需 ...
- JavaScript中return的用法详解
JavaScript中return的用法详解 最近,跟身边学前端的朋友了解,有很多人对函数中的this的用法和指向问题比较模糊,这里写一篇博客跟大家一起探讨一下this的用法和指向性问题. 1定义 t ...
随机推荐
- [CCF2015.12]题解
201512-1 数位之和 水题一个,取模除以10胡搞即可(不知道字符串为什么不行 #include <algorithm> #include <iostream> #incl ...
- cdoj 1334 郭大侠与Rabi-Ribi 贪心+数据结构
郭大侠与Rabi-Ribi Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Su ...
- javascirpt历史澄清误解基本概念特点编程语言web2.0网页javascript - javascirpt知识大全
目录1历史 2澄清误解 3基本概念 4特点 5与Java的不同 6开发工具 历史 大概在1992年,一家称作Nombas的公司开始开发一种叫做C减减(C-minus-minus,简称Cmm)的嵌入式脚 ...
- 适用于Firemonkey的Json解析对象XsuperObject使用方法介绍
XSuperObject是适用于FileMonkey平台的JSON解析组件,能够在Android,IOS,MACOS,WINDOWS等多个平台使用 点击下载 Sample JSON { "n ...
- memcached的LRU删除机制
1)memcached不会自动清空缓存的值如果add了一个值,但不去get它,那么这个值过期了,它也不会被清空.解释:memcached不自动检测和清空值,它只当你需要get这个值的时候,才检测这个值 ...
- Wireshark基本介绍和学习TCP三次握手(转)
http://www.cnblogs.com/TankXiao/archive/2012/10/10/2711777.html 之前写过一篇博客:用 Fiddler 来调试HTTP,HTTPS. 这篇 ...
- python练习程序(c100经典例20)
题目: 一球从100米高度自由落下,每次落地后反跳回原高度的一半:再落下,求它在第10次落地时,共经过多少米?第10次反弹多高? def foo(height,num): sum=height; pr ...
- ecshop 在首页每个商品下显示已销售数量
1.在includes/lib_goods.php文件末尾加入以下代码 function get_buy_sum($goods_id) { $sql = "select sum(goods_ ...
- PrintWriter的println问题
今天发现一个奇怪的问题,同样的代码web server部署在windows自测机器上跟linux服务器上, 在通信上出现了不一样的换行结束符. Debug发现通过PrintWriter的println ...
- Be quiet
Be quiet */--> UP | HOME Be quiet Table of Contents 1 Be quiet 1 Be quiet 最近心情有点不太好,各方面原因.主要是25岁是 ...