• 基本类型和引用类型

    在JavaScript中有两种数据类型值。基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指的是可能由多个值构成的对象。在JavaScript中有5种基本数据类型,分别是:Undefined、Null、Boolean、Number、String(这个和其他编程语言不一样,需要注意)。基本数据类型是按值进行访问的,一般都存储在栈中。而引用类型的值都保存在内存堆上面,在内存栈上保存一个对它的引用(这个和C#,Java等编程语言存储对象的方式类似)。在JavaScript中提供基本的引用类型数据,它们是:Object、Array、Function等。这些具体会在后面的博文介绍。

    下面我们来看下基本数据类型和引用数据类型在一些关键点上的差异。先看基本数据类型。

    例如:var num1=5;var num2=num1。基本数据类型在内存中是这样的。如图:

    而作为引用类型我们可以使用下面代码来看下其内存布局。代码如下:

 var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Hello";
alert(obj2.name); //输出Hello

    JavaScript中所有的函数参数都是值传递的。这对于基本数据类型很好理解,就是拷贝一份当前的值。函数内部使用的参数和外部传递的值互不影响。而作为引用类型的参数,这个值其实就是对象在堆内存上的引用。这个类似于上面介绍引用类型内存布局的部分。

  • 执行环境和作用域

    执行环境定义了变量或者函数有权访问的其他数据、决定了它们各自的行为。每一个环境变量都有一个与之关联的比变量对象。执行环境中定义的所有变量和函数都保存在这个变量中。

    全局执行环境是最外层的执行环境,一般在Web环境下指的是Window对象。所有全局变量和函数都是作为Window对象的属性和方法创建的。某一个执行环境的代码执行完毕以后,该环境被销毁(准确的说是从环境栈中弹出),保存在其中所有的变量和函数也都销毁了。全局执行环境需要等浏览器关闭才能退出。

    每一个函数都有自己的执行环境。当代码在一个环境中执行时,会创建变量对象的作用域链。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行环境的变量对象。作用域链中的下一个变量对象包含外部环境,再下一个变量对象则来自下一个包含环境。这样一直延续到全局执行环境。下面就通过一个例子来直观的看下这方面的内容。

    我们先来看这段简单的代码:

 function a(x,y){
var b=x+y;
return b;
}

    在函数a创建的时候它的作用域链填入全局变量对象,该变量对象中包含全局变量和函数。如图所示:

    如果执行环境是函数,那么将其活动对象(activation object, AO)作为作用域链第一个对象,第二个对象是包含环境,下一个是包含环境的包含环境(这就是我们上面讲的作用域链)。还是看代码:

 function a(x,y){
var b=x+y;
return b;
}
var tatal=a(5,10);

    这时候当执行到第5行代码,进入函数a进行执行时,作用域链如图:

  • 延长作用域链

    在JavaScript中执行环境的类型可以分成两种,全局和局部(函数)。但是有些语句在执行过程中可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。具体来说就是当执行流进入try-catch中的catch块时和with语句时会临时添加一个变量对象。但这在构建大型应该时也会造成性能损耗。

  • JavaScript参数相关知识点

    JavaScript函数中的参数和其他编程语言也是不同的。JavaScript函数不介意你到底传递多少个参数,甚至实参和形参不对应也可以,因为在函数内部JavaScript使用一个arguments对象来保存外部传递的所有参数。arguments对象是一个类似于数组的对象,它可以提供arguments[0],[1]这样的方式来访问传递过来的参数。但是它不是数组,是一个对象。

 function showArgs(arg1, arg2) {
var len1 = showArgs.length; //输出形参个数
var len2 = arguments.length;//输出实参个数
alert(len1); //输出2
alert(len2); //输出4
}
showArgs(1, 2, 3, 4);

    我们可以看到实参传递的所有参数都保存在arguments对象中,这个对象中根据下标会获取到一个个的实参。而函数对象的length只会获取该函数形参的个数。下面介绍argument的另一个重量级的属性callee。对于callee,它是一个指针,指向其函数(arguments对象所属的函数)。下面我们还是通过例子来了解这个属性。

 var sum = function sum(n) {
  var functionCode = arguments.callee.toString();
  //alert(functionCode);
  if (n <= 1) {
  return 1;
  }
  else {
  return n + arguments.callee(n - 1);
  }
  };
  alert(sum(100)); //输出5050

    这个例子是计算1+2+3+.....+99+100的。我们可以使用arguments.callee来进行递归调用。arguments.callee指向的是当前函数的指针。那一句注释掉的会输出sum函数的源代码。好了今天的博客就写到这边吧。最后再用一个例子来生动的介绍下作用域和作用域链。

  • 最后总结

  请看下面的例子

var color = "blue";
function changeColor() {
var anthorcolor = "red";
function swapColor() {
var tempColor = anthorcolor;
anthorcolor = color;
color = tempColor;
}
swapColor();
}
changeColor();

  分析如图:

分析:
  我们看到当JavaScript执行changeColor函数时,会创建的自己的一个执行环境,然后压入环境栈中。每一个执行环境都有一个与之对应的变量对象和作用域链。作用域链的前端(索引0处)始终是指向当前执行代码所在的环境的变量对象。作用域链的下一个指向的变量对象则来自下一个包含环境(父执行环境,图中是全局执行环境)。最后changeColor的变量对象中保存了swapColor函数的引用及其他一些信息。所以在changeColor中进行变量的查找时,会首先查找自己的变量对象,没有找到的话会去上一级的变量对象中查找,所以changeColor函数可以访问到anthorColor和color变量。

  下面我们来分析swapColor函数。当开始执行swapColor函数时,会往环境栈中压入一个swapColor的执行环境。这时候作用域链的前端指向的是swapColor的变量对象。这时候swapColor的作用域链最前端是其本身的变量对象,下一层指向的是changeColor的变量对象,最外面一层指向的是window的变量对象。所以在swapColor中查找color变量的时候需要先在swapColor的变量对象中查找,然后在changeColor变量环境中查找,最后在全局的变量环境中才找到。最后swapColor执行完毕后,其执行环境会从环境栈中弹出。当前的执行环境又变成changeColor。好了,介绍到这,你应该也能画出执行swapColor时的执行环境和作用域链的图了吧。

浅谈JavaScript中的变量、参数、作用域和作用域链的更多相关文章

  1. 浅谈JavaScript中的闭包

    浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...

  2. 浅谈JavaScript中的null和undefined

    浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...

  3. 浅谈JavaScript中的正则表达式(适用初学者观看)

    浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...

  4. 浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释

    浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释 下面小编就为大家带来一篇浅谈linux中shell变量$#,$@,$0,$1,$2的含义解释.小编觉得挺不错的,现在就分享给 ...

  5. 浅谈javascript函数,变量声明及作用域

    javascript函数跟变量的声明.作用域这些概念网上都已经讲烂了. 这里写个博客,也相当于做个笔记. 变量声明 首先看个例子: var globalVar = "gv"; fu ...

  6. 浅谈JavaScript中的this

    引言 JavaScript 是一种脚本语言,因此被很多人认为是简单易学的.然而情况恰恰相反,JavaScript 支持函数式编程.闭包.基于原型的继承等高级功能.本文仅采撷其中的一例:JavaScri ...

  7. 浅谈JavaScript中的内存管理

    一门语言的内存存储方式是我们学习他必须要了解的,接下来让我浅谈一下自己对他的认识. 首先说,JavaScript中的变量包含两种两种类型: 1)值类型或基本类型:undefined.null.numb ...

  8. 浅谈JavaScript中的继承

    引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ...

  9. 浅谈javascript中变量作用域和内存(1)

    先理解两个概念:基本类型和引用类型的值 1.基本类型和引用类型的值 (1)定义: 基本类型:指简单的数据段,比如按值访问的js五种基本数据类型undefined.null.boolean.number ...

随机推荐

  1. 【USACO 1.4】Arithmetic Progressions

    /* TASK: ariprog LANG:C++ URL:http://train.usaco.org/usacoprob2?a=PA9lOcZrdWq&S=ariprog SOLVE:平方 ...

  2. 寻找数组中第K频繁的元素

    问题是:给你一个数组,求解出现次数第K多的元素.当然leetcode上的要求是算法复杂度不能大于O(N*logN). 首先这个问题我先是在leetcode上看到,当时想了两种做法,做到一半都觉得不是很 ...

  3. windows下为mysql添加日志

    mysql的配置文件 [mysqld] …… log-error="D:/phpStudy/log/mysql/mysql_log_err.txt" log="D:/ph ...

  4. 二叉树遍历Java实现

    [仅贴代码及测试结果] -------------------BinaryTree.java------------------------------ class Tree<E>{ E ...

  5. python 内建类型

    ''' 数值 numbers 字符串 strings 列表 lists 字典 dictionaries 元组 tuples 文件 files 集合 sets ''' 1.1 序列的操作 所有序列类型都 ...

  6. NameNode & DataNode

    NameNode类位于org.apache.hadoop.hdfs.server.namenode包下. NameNode serves as both directory namespace man ...

  7. jdbc实现事务

    //conn需要自己获取,这里我用的时springjdbcTemplate Connection conn = null; PreparedStatement pstm = null; try { c ...

  8. Jenkins/CCNET发送邮件策略和注意事项,以及邮箱类型的选择

    QQ邮箱永远也不要用,原因:安全机制太强导致在CCNET/Jenkins中极难配置,且反垃圾太强,有些项目会涉及到敏感词一样屏蔽,如果发邮件找客服求助时,基本是无果. 如果在免费领域,推荐使用免费企业 ...

  9. C#的Invoke和BeginInvoke

    在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate,至于委托的本质请参考我的另一随笔:对.net事件的看法. 一.为什么Control类提供了Invoke和Begin ...

  10. Objective-C 中基于RunTime实现的反射

    一.反射 反射,一般表现在字符串和Class转换,字符串和内部方法转换,字符串和属性的转换(取值和赋值). 二.Objective-C中的反射 OC的反射是基于其Runtime实现的. 以执行某个函数 ...