简单谈谈javascript中的变量、作用域和内存问题


Posted in Javascript onAugust 30, 2015

【变量】

[1]定义:可变的量,相当于给一个不定的数据起了一个外号。变量是存储信息的容器。
[2]特性:js中的变量是松散类型的,可以保存任何类型的数据。它只是在特定时间用于保存特定值的一个名字而已。由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变。
[3]变量声明:变量可以在声明时赋值,但不能有其他操作,如+=、-=等

var a = 2;//是正确的
var a += 2;//是错误的
var a = 2++;//是错误的,++只能用于变量,不能用于常量

[4]注意:用var操作符定义的变量将成为定义该变量的作用域中的局部变量。若省略var操作符,可以创建一个全局变量,但在严格模式下会抛出 ReferenceError错误

[5]var:使用var声明的变量会自动被添加到最接近的环境中。如果初始化变量时没有使用var声明,该变量会自动被添加到全局环境。在严格模式下,初始化未经声明的变量会导致错误。
[6]局部变量:如果局部环境中存在同名标识符,就不会使用位于父环境中的标识符。任何位于局部变量color的声明之后的代码,如果不使用window.color都无法访问全局color变量

【标识符】

[1]定义:变量、函数、属性的名字,或者函数的参数。
[2]注意:

[2.1]第一个字符必须是一个字母、下划线或一个美元符号。其他字符可以是字母、下划线、美元符号或数字[不能出现中划线]

[2.2]标识符中的字母也可以包括拓展的ASCII或Unicode字母字符,可以使用中文

[2.3]标识符应采用小驼峰格式,第一位应该是数据的类型,常见的标识如下:

数组 

a 
Array aItems


布尔值  
b 
Boolean bIsComplete


浮点数  
f 
 FLoat fPrice


函数 

fn   Function fnHandler


整数 

i 
 Integer iItemCount


对象 

o 
Object oDIv1


正则表达式  re   RegExp reEmailCheck


字符串 
  s 
 String sUserName


变量
 
v 
Variant vAnything

[2.4]不能把关键字、保留字、true、false和null用作标识符

[2.5]对于不符合标识符命名规则的属性如background-color应写为大括号方式[backgroundColor]
[3]标识符解析:标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级地向后回溯,直到找到标识符为止(如果找不到标识符,表示标识符尚未声明,通常会导致错误发生)。

[3.1]如果局部环境中存在着同名标识符,就不会使用父环境中的标识符

e.g. 全局和局部有同名标识符color,任何位于局部变量color的声明之后的代码,如果不使用window.color都无法访问全局color变量

[3.2]JavaScript引擎在优化标识符查询方面做得不错,访问全局变量和局部变量的时间差别可以忽略不计

【作用域】(也称为执行环境)

[注意]javascript中没有块级作用域 
[1]执行环境:执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之相关联的变量对象。环境中定义的所有变量和函数都保存在这个对象中。

[2]全局执行环境:

[2.1]全局执行环境是最外围的一个执行环境,在web浏览器中,全局执行环境被认为是window对象。因此所有全局变量和函数都是作为window对象的属性和方法创建的。全局执行环境直到应用程序退出例如关闭网页或浏览器时才会被销毁

[2.2]一个页面就相当于一个全局作用域。不论是页面中的js代码,还是引用的外部js文件,最终都会按照在页面中的先后依次解析。

[3]函数执行环境:每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

[4]作用域链:当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问。作用域的前端始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。活动对象在最开始时只包含一个变量,即arguments对象(这个对象在全局环境中是不存在的)。作用域链中的下一个变量对象来自包含环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

[4.1]作用域链的特点:内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。这些环境之间的联系是线性、有次序的。每个环境都可以向上搜索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个执行环境。

[5]延长作用域链:

[5.1]try-catch语句:catch块会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明

[5.2]with语句:会将指定的对象添加到作用域链中

function buildUrl(){
  var qs = '?debug=true';
  with(location){
    var url = href + qs;
  }
  return url;
}

【垃圾回收】:javascript具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存。

[1]垃圾回收机制:找出那些不再继续使用的变量,然后释放其占用的内存,垃圾收集器会按照固定的时间间隔,或代码执行中预定的收集时间,周期性地执行这一操作

[2]垃圾收集标记无用变量的两种策略

[2.1]标记清除,标记“进入环境”和“离开环境”。离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除

[2.2]引用计数,跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1,如果同一个值又被赋给另一个变量,则该值的引用次数加1,相反,如果包含对这个值的引用的变量又取得了另外一个值,则这个值的引用次数减1,当这个值的引用次数为0时,则说明没有办法再访问这个值了,因此就可以将其占用的内存空间回收回来。

[2.2.1]引用计数的问题:循环引用:对象A中包含一个指向对象B的指针,对象B中也包含一个指向对象A的指针

[2.2.2]IE:IE中有一部分对象并不是原生js对象,例如,其BOM和DOM中的对象就是使用c++以COM对象的形式实现,而COM对象的垃圾回收机制采用的就是引用计数策略

var element = document.getElementById('some_element');
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;

解决办法:为了避免类似这样的循环引用,最好是在不使用它们的时候手工断开

myObject.element = null;
element.someObject = null;   

为了解决此问题,IE9把BOM和DOM对象都转换成了真正的js对象

【内存管理】

[1]主要问题:分配给web浏览器的可用内存数量通常要比分配给桌面应用程序的少,目的是防止运行js的网页耗尽全部系统内存而导致系统崩溃。内在限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量 

[2]优化方式:为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为null来释放其引用,这种做法叫解除引用。这一做法适用于大多数全局变量和全局对象的属性以及循环引用变量,局部变量会在它们离开执行环境时自动被解除引用。

解除变量的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。

Javascript 相关文章推荐
云网广告中的代码,提示出错,大家找找
Nov 21 Javascript
Jquery Ajax学习实例 向页面发出请求,返回XML格式数据
Mar 14 Javascript
jQuery Study Notes学习笔记 (二)
Aug 04 Javascript
js中Math之random,round,ceil,floor的用法总结
Dec 26 Javascript
JavaScript中的标签语句用法分析
Feb 10 Javascript
javascript鼠标右键菜单自定义效果
Dec 08 Javascript
bootstrap模态框垂直居中效果
Dec 03 Javascript
VueJs与ReactJS和AngularJS的异同点
Dec 12 Javascript
在 Angular中 使用 Lodash 的方法
Feb 11 Javascript
Node.js npm命令运行node.js脚本的方法
Oct 10 Javascript
小程序实现单选多选功能
Nov 04 Javascript
Vue 开发必须知道的36个技巧(小结)
Oct 09 Javascript
jquery专业的导航菜单特效代码分享
Aug 29 #Javascript
js实现基于正则表达式的轻量提示插件
Aug 29 #Javascript
js精美的幻灯片画集特效代码分享
Aug 29 #Javascript
jQuery实现淡入淡出二级下拉导航菜单的方法
Aug 28 #Javascript
jquery实现清新实用的网页菜单效果
Aug 28 #Javascript
jquery左右全屏大尺寸多图滑动效果代码分享
Aug 28 #Javascript
jQuery实现多级下拉菜单jDropMenu的方法
Aug 28 #Javascript
You might like
PHP的SQL注入实现(测试代码安全不错)
2011/02/27 PHP
基于MySQL到MongoDB简易对照表的详解
2013/06/03 PHP
如何写php守护进程(Daemon)
2015/12/30 PHP
php微信公众平台开发(四)回复功能开发
2016/12/06 PHP
ThinkPHP实现登录退出功能
2017/06/29 PHP
小程序微信支付功能配置方法示例详解【基于thinkPHP】
2019/05/05 PHP
JQuery onload、ready概念介绍及使用方法
2013/04/27 Javascript
借助javascript代码判断网页是静态还是伪静态
2014/05/05 Javascript
jQuery添加删除DOM元素方法详解
2016/01/18 Javascript
微信小程序 WXML、WXSS 和JS介绍及详解
2016/10/08 Javascript
浅谈Javascript中的函数、this以及原型
2016/10/09 Javascript
详解js的六大数据类型
2016/12/27 Javascript
jquery拖动改变div大小
2017/07/04 jQuery
基于Bootstrap实现城市三级联动
2017/11/23 Javascript
Vue中的无限加载vue-infinite-loading的方法
2018/04/08 Javascript
webpack4的迁移的使用方法
2018/05/25 Javascript
JavaScript查看代码运行效率console.time()与console.timeEnd()用法
2019/01/18 Javascript
vue组件化中slot的基本使用方法
2019/05/01 Javascript
JS实现点击下拉列表文本框中出现对应的网址,点击跳转按钮实现跳转
2019/11/25 Javascript
基于vue实现简易打地鼠游戏
2020/08/21 Javascript
[07:43]《辉夜杯》公开赛晋级外卡赛战队—TRG训练生活探秘
2015/12/11 DOTA
[40:55]DOTA2上海特级锦标赛主赛事日 - 2 败者组第二轮#4Newbee VS Fnatic
2016/03/03 DOTA
PyQt5每天必学之创建窗口居中效果
2018/04/19 Python
pycharm下查看python的变量类型和变量内容的方法
2018/06/26 Python
python 随机打乱 图片和对应的标签方法
2018/12/14 Python
对Python中小整数对象池和大整数对象池的使用详解
2019/07/09 Python
python函数装饰器之带参数的函数和带参数的装饰器用法示例
2019/11/06 Python
python文件操作的简单方法总结
2019/11/07 Python
Django中ORM找出内容不为空的数据实例
2020/05/20 Python
澳大利亚买卖正宗二手奢侈品交易平台:Luxe.It.Fwd
2019/10/16 全球购物
运动会演讲稿50字
2014/08/25 职场文书
法人委托书范本
2014/09/15 职场文书
兵马俑的导游词
2015/02/02 职场文书
2015年妇委会工作总结
2015/05/22 职场文书
2015年全民创业工作总结
2015/07/23 职场文书
mongodb数据库迁移变更的解决方案
2021/09/04 MongoDB