简单谈谈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 相关文章推荐
javascript 命名空间以提高代码重用性
Nov 13 Javascript
JavaScript高级程序设计阅读笔记(五) ECMAScript中的运算符(一)
Feb 27 Javascript
js中浮点型运算BUG的解决方法说明
Jan 06 Javascript
Jquery数字上下滚动动态切换插件
Aug 08 Javascript
gameboy网页闯关游戏(riddle webgame)--仿微信聊天的前端页面设计和难点
Feb 21 Javascript
详解JS正则replace的使用方法
Mar 06 Javascript
javascript 开发之网页兼容各种浏览器
Sep 28 Javascript
微信小程序自定义prompt组件步骤详解
Jun 12 Javascript
JavaScript基于对象方法实现数组去重及排序操作示例
Jul 10 Javascript
浅谈JavaScript_DOM学习篇_图片切换小案例
Mar 19 Javascript
微信小程序自定义顶部组件customHeader的示例代码
Jun 03 Javascript
vue watch监控对象的简单方法示例
Jan 07 Vue.js
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
ThinkPHP文件缓存类代码分享
2015/04/22 PHP
我整理的PHP 7.0主要新特性
2016/01/07 PHP
锋利的jQuery 要点归纳(三) jQuery中的事件和动画(下:动画篇)
2010/03/24 Javascript
jQuery动态创建html元素的常用方法汇总
2014/09/05 Javascript
JavaScript模拟重力状态下抛物运动的方法
2015/03/03 Javascript
jquery实现点击label的同时触发文本框点击事件的方法
2015/06/05 Javascript
剖析Node.js异步编程中的回调与代码设计模式
2016/02/16 Javascript
Node.js的MongoDB驱动Mongoose基本使用教程
2016/03/01 Javascript
js事件处理程序跨浏览器解决方案
2016/03/27 Javascript
jQuery Mobile 和 Kendo UI 的比较
2016/05/05 Javascript
微信小程序loading组件显示载入动画用法示例【附源码下载】
2017/12/09 Javascript
vue数据传递--我有特殊的实现技巧
2018/03/20 Javascript
详解使用vue-admin-template的优化历程
2018/05/20 Javascript
[40:10]2015国际邀请赛全明星表演赛
2015/08/07 DOTA
使用Python实现简单的服务器功能
2017/08/25 Python
人生苦短我用python python如何快速入门?
2018/03/12 Python
python Web开发你要理解的WSGI & uwsgi详解
2018/08/01 Python
python-opencv颜色提取分割方法
2018/12/08 Python
python 求某条线上特定x值或y值的点坐标方法
2019/07/09 Python
python实现桌面托盘气泡提示
2019/07/29 Python
pytorch实现特殊的Module--Sqeuential三种写法
2020/01/15 Python
Python GUI编程学习笔记之tkinter界面布局显示详解
2020/03/30 Python
python对接ihuyi实现短信验证码发送
2020/05/10 Python
python tkiner实现 一个小小的图片翻页功能的示例代码
2020/06/24 Python
浅析Python 多行匹配模式
2020/07/24 Python
HTML5实现晶莹剔透的雨滴特效
2014/05/14 HTML / CSS
去加拿大的旅行和假期:Canadian Affair
2016/10/25 全球购物
中国海淘族值得信赖的海淘返利网站:55海淘
2017/01/16 全球购物
美国豪华的多品牌精品店:The Webster
2019/07/31 全球购物
财务会计应届生求职信
2013/11/24 职场文书
关于毕业的中学校园广播稿
2014/01/26 职场文书
喷漆工的岗位职责
2014/03/17 职场文书
毕业实习计划书
2015/01/16 职场文书
react中的DOM操作实现
2021/06/30 Javascript
SpringBoot集成MongoDB实现文件上传的步骤
2022/04/18 MongoDB
html中两种获取标签内的值的方法
2022/06/10 HTML / CSS