JavaScript 中变量、作用域和内存问题的学习
这是我学习JavaScript的第二篇文章,之前做过几年的Java开发,发现JavaScript虽然也是面向对象的语言但是确实有很多不同之处。就本篇博客,主要学习总结一下最近学习到的JavaScript的知识,其中有些是网络上的,不过对于理解JavaScript,和在工作总是会很实用的,所以总结了下来:
那么就开始吧,首先是变量
在JavaScript中变量分为两种:一种是基本类型,基本类型值在内存中占用固定大小的空间,因此被保存在栈内存中。从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本。另一种类型则是引用类型,引用类型的值是对象,保存在堆内存中,对象的引用保存在栈中。包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向对象的指针,从一个变量向另一个变量复制引用类型的值,复制的是指针,最终指向同一个对象。
那么在实际的使用中要确定一个值是那种基本类型的可以使用typeof操作符,而确定一个值是哪种引用类型则需要使用instanceof 操作符。
基本数据类型:undefined、Null、boolean、number和String
引用类型:Object、Array、Date、RegExp、Function、基本包装类型、单体内置对象(Gloabal、Math)。关于引用类型各个类型的详细使用,下次再详细描述。
JavaScript是面向对象的语言,同样支持继承,只是JavaScript支持实现继承,不支持接口继承。
JavaScript是一种非强类型的语言,不需要严格的如同Java、C等语言的声明类型然后复制,也一定要赋值声明类型的值。JavaScript有两种值类型,所以涉及到两个地方复制,一种就是复制变量值,另一个则是方法调用的时候存在参数传递赋值。基本类型是值复制,引用类型复制是对象的引用。
作用域
js中没有块作用域的概念。在没有var进行声明则会生成为全局变量污染全局环境。所以在实际的使用过程中,一定要记得var,js对变量的搜索是一层一层往上搜索,如果搜索到变量则停止往上搜索(所以搜索变量的层次越多肯定会小小的影响程序性能)。
延长作用域链
虽然执行环境的类型总共只有两种--全局和局部(函数),但还是有其他办法来延长作用域链。这是因为有些语句可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。那么具体是哪写情况呢?具体就两种:
(1)、try-catch 语句的catch块。
(2)、with语句块。
这两个语句都会在作用域链的前端添加一个变量对象。对with语句来说会指定对象添加到作用域链中。对catch语句来说,会创建一个新的变量对象,其中包含的是被抛出的对象的声明。所以在try-catch 和with要慎用,with是不推荐使用的。在严格模式下,是不能使用,但是我们要对with有一些了解。用一个例子解说:
with(location){
var qs=search.substring(1);
var hostname=hostname;
var url=href;
}
href 和hostname 都是location.hostname 和location.url
好了,稍后来说一下JS的执行环境,js的执行环境是很复杂的,我肯定也是不能全部说清楚的,下面就根据我所了解的简单总结了几个重点,后期了解到更多后,在加入到本次的博客中。
执行环境和全局执行环境、异步执行机制、事件和回调函数、Event Loop、定时器、Js垃圾收集 这六个方面。
1、执行环境和全局执行环境
执行环境有全局执行环境(也称为全局环境)和函数执行环境之分。
每次进入一个新环境,都会创建一个用于搜索变量和函数的作用域链,这些搜索向前面说的一样,是一层一层向上搜索的。
函数的的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,乃至全局环境。
有全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据。变量的执行环境有助于确定应该何时释放内存。
2、异步执行机制
JavaScript是单线程的,也就是说同一个时间只能做一件事情。那么所有的任务需要排队执行,如果某一个任务执行很慢,则会影响整个性能,那么JavaScript又是怎么处理的呢?
JavaScript中的任务分为两种:一种是同步任务,另一种是异步任务;也就是synchronous 和asynchronous 两种任务。同步任务指的是在主线程上排队执行的任务。异步任务指的是,不进入主线程,而进入任务队列(task queue)的任务,只有“任务队列” 通知主线程,某个异步任务可执行了,该任务才会进入主线程执行。
异步执行的允许机制如下:
(1)、所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)、在主线程队列之外,还存在一个任务队列。只要异步任务有了运行结果,就在任务队列中放置一个事件。
(3)、一旦“执行栈”中的所有同步任务执行完成,系统就会查询“任务队列”,有哪些事件,哪些对应的异步任务,于是结束等待状态,进入执行栈。开始执行。
(4)、主线程不断重复上面的(3)。
只要主线程空了,就会读取“任务队列”。
3、事件和回调函数
“任务队列”是一个事件的队列,IO设备、鼠标点击、页面滚动等等,完成一项任务,就在“任务队列”中添加一个事件,表示相关的异步任务可以进入“执行栈”。也就是主线程执行的队列中。主线程执行。
所谓“回调函数”(callback),就是哪些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的callback函数。
“任务队列”,要等到主线程将主线程中的执行队列执行完之后,就进入执行任务队列。但是,由于存在后文提到的“定时器”功能,主线程首先要检查一下执行时间,某些时间只有到了规定的时间,才能返回主线程。
4、Event Loop

主线程从“任务队列”中读取事件,这个过程是不断循环,所以整个的这种运行机制称为Event Loop。一个进程只能执行一个任务要能执行多个任务,需要下面三种方法:
(1)、排队。因为一个进程一次只能执行一个任务,只好等当前的任务执行完了,再执行后面的任务。
(2)、新建进程。使用fork新建一个进程。
(3)、新建线程。因为进程太耗费资源,可以使用进程进行多任务执行。
JavaScript则是排队的方式处理的,但是存在一个始终运行的Event loop来进行监控哪些事件需要触发,如果需要触发,则通知主线程执行回调函数。也就是上面描述2、异步执行机制中的 (3)、(4)中的(3)。这样主线程在任务多的时候达到任务饱和。不像多线程中那样存在多个线程的上下文和执行环境的切换的消耗。
5、定时器
了解了上面的事件回调合 任务队列,那么定时器这个异步任务事件,就能很好的理解啦,即指定某些代码在多少时间之后执行。这叫“定时器”功能,也就是定时执行的代码。定时器功能有setTimeout()和setInterval()这两个函数来完成,它们的内部运行机制完全一样,区别是前者指定的代码是一次执行,后者反复执行。setTimeout()的第二个参数为0,就表示当前主线程任务清空后。立即执行指定的回调函数。 这种方式可以将耗时的方法,setTimeout到任务队列中,任务队列中存在先后顺序。
6、Js垃圾回收
上面说到执行环境有助于垃圾回收,是什么意思呢?就是离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除。
现在垃圾收集比较常用的都是“标记删除”,这种算法的思想是给当前不使用的值加上标记,然后再回收其内存。
还有一种“引用计数算法”,这种算法的思想是跟踪记录所有值被引用的次数。之前IE在使用,但是现在JavaScript不再使用这种算法,因为可能会出现内存泄漏的问题,具体为什么,如果代码中存在循环引用现象,将会导致泄漏。垃圾收集器是周期性运行的,而且如果为变量分配的内存数量很乐观,那么回收的工作量也是相当大的。如果需要清理的空间大。这种情况下,确定垃圾收集的事件间隔是一个非常重要的问题,存在垃圾收集机制的语言编写代码比较方便,但是内部的机制也相对比较复杂,确保占用的内存少可以让页面得到好更好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不不再有用,最后通过将其设置为null来释放引用 这种做法叫做解除引用。这一做法适用于大多数全局变量和全局变量的熟悉。局部变量会在它们离开执行环境的时候自动解除引用。解除一个值的引用并不意味着自动回收该值占用的内存,而是表示该空间可以回收。解除引用的真正的目的也是让值脱离执行环境,以便垃圾收集器下次回收其空间。
关于JavaScipt的运行机制我总结的肯定不一定准确全面,希望在今后的工作和学习中,更加了解,这样才能知其然,并知其所以然。
参考资料
《JavaScript高级程序设计》
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
JavaScript 中变量、作用域和内存问题的学习的更多相关文章
- 浅谈javascript中变量作用域和内存(2)
1.无块级作用域 javascript没有块级作用域,这会让其他程序员在理解js代码上很痛苦.在其他很多语言,比如C,大括号括起来的代码块都有自己的作用域 举个例子 if(true) { var na ...
- 浅谈javascript中变量作用域和内存(1)
先理解两个概念:基本类型和引用类型的值 1.基本类型和引用类型的值 (1)定义: 基本类型:指简单的数据段,比如按值访问的js五种基本数据类型undefined.null.boolean.number ...
- Javascript中变量作用域(2)
多层函数调用取变量时,无论在哪里调用,要到创建此函数的作用域中取值,如果找不到再往上一级,直到全局变量. 外面定义了很多的全局的变量,下面我们来一个个理一下. 定义三个变量a,b,c;将A1函数赋值给 ...
- Javascript中变量作用域
<script type="text/javascript"> var a = 10; var Bar = (function () { console.log(a); ...
- 第一百零六节,JavaScript变量作用域及内存
JavaScript变量作用域及内存 学习要点: 1.变量及作用域 2.内存问题 JavaScript的变量与其他语言的变量有很大区别.JavaScript变量是松散型的(不强制类型)本质,决定了它只 ...
- javascript的变量作用域--对比js、php和c的for循环
为什么要写这篇文章呢?主要是给自己提个醒,js的水很深,需要小心点儿才能趟过去,更何况自己不是专业人士,那就得更加小心了. 看下面的js代码: <!DOCTYPE html> <ht ...
- [转]深入理解JavaScript的变量作用域
1.JavaScript的作用域链 2.函数体内部,局部变量的优先级比同名的全局变量高. 3.JavaScript没有块级作用域. 4.函数中声明的变量在整个函数中都有定义. 5.未使用var关键字定 ...
- JavaScript中的作用域
很多(JavaScript)开发者都在讨论"作用域",但它是什么?它们在JavaScript中的任何地方!我发现很多年轻的开发者不知道作用域是什么.他们中大多数人可以用jQuery ...
- 深入理解JavaScript的变量作用域(转载Rain Man之作)
在学习JavaScript的变量作用域之前,我们应当明确几点: JavaScript的变量作用域是基于其特有的作用域链的. JavaScript没有块级作用域. 函数中声明的变量在整个函数中都有定义. ...
随机推荐
- 15个最好的PDF转word的在线转换器,将PDF文件转换成doc文件
PDF是一种文件格式,包含文本,图像,数据等,这是独立于操作系统的文件类型.它是一个开放的标准,压缩,另一方面DOC文件和矢量图形是由微软文字处理文件.该文件格式将纯文本格式转换为格式化文档.它支持几 ...
- Spectrum to XYZ to sRGB
如何将频谱响应转换为对应的RGB显示值: 首先要在频率功率分布(SPD)曲线的基础上,分别使用X/Y/Z三个频率匹配曲线(spectral matching curves,又名CIE XYZ Colo ...
- Swift中对C语言接口缓存的使用以及数组、字符串转为指针类型的方法
由于Swift编程语言属于上层编程语言,而Swift中由于为了低层的高性能计算接口,所以往往需要C语言中的指针类型,由此,在Swift编程语言刚诞生的时候就有了UnsafePointer与Unsafe ...
- 小试ijkplayer编译
同步发表于 http://avenwu.net/ijkplayer/2015/05/07/hands_on_ijkplayer_preparation 谈到视频播放大家都知道ffmpeg,基于其的衍生 ...
- 关于meta知多少
本来打算写关于手机端的知识,想了想先从meta着手.接下来请大家看几个网站的例子. 一.天猫(http://m.tmall.com) <title>天猫触屏版</title> ...
- ASP.NET 回调技术(CallBack)
在asp.net中客户端与服务器端的交互默认都是整页面提交, 此时客户端将当前页面表单中的数据(包括一些自动生成的隐藏域)都提交到服务器端,服务器重新实例化一个当前页面类的实例响应这个请求,然后将整个 ...
- Flash播放mp4的两个问题:编码问题和需要下载完后才能播放的问题
(1)编码问题.需要是 h.264 编码,不是此编码的在某些Flash版本或OS上会出现放不出来视频的问题:可以用 3GP.MP4视频转换精灵(BRVideoConverter) 转码. (2)下载完 ...
- Windows内核安全与驱动开发
这篇是计算机中Windows Mobile/Symbian类的优质预售推荐<Windows内核安全与驱动开发>. 编辑推荐 本书适合计算机安全软件从业人员.计算机相关专业院校学生以及有一定 ...
- 移植UE4的模型操作到Unity中
最近在Unity上要写一个东东,功能差不多就是在Unity编辑器上的旋转,移动这些,在手机上也能比较容易操作最好,原来用Axiom3D写过一个类似的,有许多位置并不好用,刚好在研究UE4的源码,在模型 ...
- Unity3d 在不同设备中的文件读写 的路径
Application.dataPath : 数据路径 Unity Editor: <path tp project folder>/Assets Unity 编辑器:<工程文件 ...