var test=100;
function foo(){
console.log(test);//undefined
var test=200;
console.log(test);//
}

我们明明定义了一个全局变量test,按照JS作用域链的理论,func应该可以访问到全部变量test的啊?

是的,按照作用域链的思想,func函数在运行时,在其局部变量内找不到test变量的话,理应向上在全部作用局中继续查找。

问题就出在函数内部的 var test =200; 这句局部变量定义。

我们都知道JS变量类型是松散型,松散型的意思并不是说JS变量就没有变量类型,而是其变量类型是在运行时才进行确定。

var str;

str=2015;

第一行我们定义了一个变量str,但是并未赋值,这时候JS并不知道str变量的类型,等到脚本运行到第3行,我们给str变量赋了一个值:2015.

  这时候JS才知道,哦,原来str的值是2015,这不就是Number类型吗,这才确定了str的类型。

  这让我想起了JS的另一个概念,叫作函数声明提升!

 var test = 100;

func();

  function func(){
console.log(test);
var test=200;
console.log(test);
}

将函数的声明放在了最后,但是代码仍然可以正常运行,并不会出现func未定义的错误。

  函数声明提升就说明JS在运行之前还会经历另外一个过程:预加载。(有些地方也叫作预编译)

  在预加载阶段,JS主要对全局作用域、函数的运行环境以及作用域链等进行准备,

  这里的函数运行环境就是指:读取变量定义并确定其属于哪个作用域,但不会为其赋值!

   在预加载阶段,第一行的时候定义了一个全部变量a,然后到了第7行,又给func定义了一个局部变量a,

  注意这个时候变量并未赋值,值均为undefined

  到了运行阶段:

  第一行给全部变量test赋了值:100,等到执行func函数的时候,

  在第6行,需要使用test变量,JS当然是先查找func的局部变量了,没错,预加载阶段已经为func定义了一个局部变量test,

  所以JS当然不会继续往全局进行查找了,但是使用的时候才发现居然没有值,也就是undefined!

  等到第7行JS才给局部变量test赋值。

  小结:

    JS分为预加载和执行期两个阶段,前者只会确定变量的作用域,在执行期才会对齐进行赋值,同时也就确定了变量的具体类型。

 大家都知道,JavaScript中的变量类型分为两种,一种是基本数据类型,包括:undefined,null,Number,String,Boolean,另外一种就是对象。

  两种数据类型的存储方式在JS中也有所不同。

  另外,内存分为栈区(stack)和堆区(heap),然后在JS中开发人员并不能直接操作堆区,堆区数据由JS引擎操作完成,那这二者在存储数据上到底有什么区别呢?

  我们简单的通过下面这张图来分析:

  

  JS中变量的定义在内存中包括三个部分:

  • 变量标示  (比如上图中的Str,变量标示存储在内存的栈区)
  • 变量值     (比如上面中的Str的值souvenir或者是obj1对象的指向堆区地址,这个值也是存储在栈区)
  • 对象        (比如上图中的对象1或者对象2,对象存储在堆区)

  也就是说,对于基本数据类型来说,只使用了内存的栈区。

在JS预加载阶段,JS引擎只是在内存的栈区为每个变量分配了内存,指定了标示符,并未为其指定值。

  等到JS执行期才会为其赋值。

 1 var a=100;
2 var obj1={
3 attr:'hello'
4 };
5
6 func(a,obj1);
7
8 function func(num,obj){
9 var a2=num;
10 a2=200;
11
12 var obj2=obj;
13 obj2.attr='hello';
14 }
15
16 console.log(a);
17 console.log(obj1.attr);

 对于基本数据类型,在执行第9行时,JS是把num在栈区的值,也就是100复制给了a2这个局部变量,然后在第10行又修改了a2的值,

  这个操作过程并未影响到全局变量a的值。

  小结:

  对于对象来说,当JS执行12行的时候,实际上是把obj在栈区的值,也就是obj对象在堆区的引用地址,复制给了新的局部变量obj2,

  这时候,obj2与obj实际上已经指向了同一个堆区的对象,然后obj2修改了这个对象的某个属性值。然后函数执行完毕,obj2这个局部变量没有引用将会被GC回收。

  再次访问obj1这个全局变量时,其所指向的对象其实已经被修改过了。

http://www.cnblogs.com/souvenir/p/4969565.html

JavaScript变量存储浅析的更多相关文章

  1. JavaScript变量存储浅析(二)

    Hello,上一篇(http://www.cnblogs.com/souvenir/p/4969399.html)我们简单的分享了JS中的变量存储原理,但是并未结束,我们漏掉了什么. 对了,就是关于对 ...

  2. JavaScript变量存储浅析(一)

    Hello! 上一篇关于JS中函数传参(http://www.cnblogs.com/souvenir/p/4969092.html)的介绍中提到了JS的另外一个基本概念:JS变量存储, 今天我们就用 ...

  3. javascript变量浅析

    变量声明 javascript 使用var + 变量名 声明变量,因为javascript是弱类型语言, 所有我们可以随意更改已有变量的类型. var b=1; b='2', 另外不同于c#中的var ...

  4. javascript变量的作用域

    javascript变量的作用域 基本类型和引用类型 基本类型值指的是简单的数据段,而引用类型值指的是那个可能由多个值组成的对象  讲一个值赋值给变量时,javascript解析器首先要确定是基本类型 ...

  5. JavaScript 变量

    一,JavaScript 变量(存储信息的容器) 与代数一样,JavaScript 变量可用于存放值(比如 x=2)和表达式(比如 z=x+y). 变量可以使用短名称(比如 x 和 y),也可以使用描 ...

  6. 六天玩转javascript:javascript变量与表达式(1)

    说明 本系列属于进阶系列,语常用语法等不在本系列介绍范围之内. 在我刚开始做一个程序员并开发项目的时候,我总是喜欢使用开发语言的各种特性,每次m$发布新版C#的时候我总是会把开发者预览版下好,亲自体验 ...

  7. 深入浅出 JavaScript 变量、作用域和内存 v 0.5

    本文主要从原理入手分享变量和作用域的相关知识,最后结合本文所分享知识,再次深入了解下闭包的运行原理. 主要参考<JS高级程序设计> <JS权威指南> <高性能 JS> ...

  8. JavaScript运行机制浅析

    从一个简单的问题谈起: <script type="text/javascript"> alert(i); var i = 1; </script> 输出结 ...

  9. 2015第35周五JavaScript变量

    java语言里有一句很经典的话:在java的世界里,一切皆是对象. Javascript虽然跟java没有半点毛关系,但是很多会使用javascript的朋友同样认为:在javascript的世界里, ...

随机推荐

  1. AngularJS -- Bootstrap(启动器)

    点击查看AngularJS系列目录 转载请注明出处:http://www.cnblogs.com/leosx/ Bootstrap(初始化) 这章介绍了Angular的初始化过程,以及如何在必要的时候 ...

  2. PHP常用数组(Array)函数整理

    整理了一份PHP开发中数组操作大全,包含有数组操作的基本函数.数组的分段和填充.数组与栈.数组与列队.回调函数.排序.计算.其他的数组函数等. 一.数组操作的基本函数 数组的键名和值 array_va ...

  3. .NET第四章总结

    .NET第四章简单总结 1.简单的获取文件路径:                    2.回车跳转控件焦点    3.*************无标题窗体拖动!!************* 1): ...

  4. OWLQN算法

    一.BFGS算法 算法思想如下: Step1   取初始点,初始正定矩阵,允许误差,令: Step2   计算: Step3   计算,使得 : Step4    令: Step5    如果,则取为 ...

  5. JQ判断浏览器以及版本

    JQuery 使用jQuery.browser 来判断浏览器,返回值可以为: safari(safari) opera(Opera) msie(IE) mozilla(Firefox). if($.b ...

  6. 一个强迫症的Git 选择

    选择 1,经常性的commit or 干净的历史 在本地(私有)的开发分支中,选择经常性的commit,以便于实时记录修改,回退等操作.eg.develop,feature... 实现方式: comm ...

  7. ssi服务器端指令详解(shtml)

    你是否曾经或正在为如何能够在最短的时间内完成对一个包含上千个页面的网站的修改而苦恼?那么可以看一下本文的介绍,或许能够对你有所帮助. 什么是SSI? SSI是英文Server Side Include ...

  8. zabbix部署

    zabbix部署 ----2016年年终总结 二 服务器端安装   yum install zabbix-server 客户端安装 yum install zabbix-agent 配置Server ...

  9. java类加载小记

    java类只有当创建实体或被调用时才会加载,加载时按 编码顺序 先加载static后加载普通的.static模块和static变量都是同一等级的,谁写前面就先加载谁. 在调用某个静态类的方法时,会按编 ...

  10. WCF的客户端与服务端

    服务端 : 1.新增一个Winform的服务端 2.选择以上建的项目,增加一个WCF服务 3.定义三个方法,一个不返回结果不带参数.返回结果带参数.返回结果以类的方式传递参数 4.Service1继承 ...