浅谈JavaScript中的变量、参数、作用域和作用域链
- 基本类型和引用类型
在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中的变量、参数、作用域和作用域链的更多相关文章
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
- 浅谈JavaScript中的null和undefined
浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...
- 浅谈JavaScript中的正则表达式(适用初学者观看)
浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...
- 浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释
浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释 下面小编就为大家带来一篇浅谈linux中shell变量$#,$@,$0,$1,$2的含义解释.小编觉得挺不错的,现在就分享给 ...
- 浅谈javascript函数,变量声明及作用域
javascript函数跟变量的声明.作用域这些概念网上都已经讲烂了. 这里写个博客,也相当于做个笔记. 变量声明 首先看个例子: var globalVar = "gv"; fu ...
- 浅谈JavaScript中的this
引言 JavaScript 是一种脚本语言,因此被很多人认为是简单易学的.然而情况恰恰相反,JavaScript 支持函数式编程.闭包.基于原型的继承等高级功能.本文仅采撷其中的一例:JavaScri ...
- 浅谈JavaScript中的内存管理
一门语言的内存存储方式是我们学习他必须要了解的,接下来让我浅谈一下自己对他的认识. 首先说,JavaScript中的变量包含两种两种类型: 1)值类型或基本类型:undefined.null.numb ...
- 浅谈JavaScript中的继承
引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ...
- 浅谈javascript中变量作用域和内存(1)
先理解两个概念:基本类型和引用类型的值 1.基本类型和引用类型的值 (1)定义: 基本类型:指简单的数据段,比如按值访问的js五种基本数据类型undefined.null.boolean.number ...
随机推荐
- 最简实例说明wait、notify、notifyAll的使用方法
wait().notify().notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态. 这三个方法最终调用的都是jvm级的native方法.随着jvm运行平台的不同可能有些 ...
- [转]git在eclipse中的配置
一_安装EGIT插件 http://download.eclipse.org/egit/updates/ 或者使用Eclipse Marketplace,搜索EGit 二_使用EGIT前的配置 配置个 ...
- UItextView回收键盘的几种方式
1.如果你程序是有导航条的,可以在导航条上面加多一个Done的按钮,用来退出键盘,当然要先实UITextViewDelegate. 代码如下: - (void)textViewDidBeginEdit ...
- 60.Android通用流行框架大全
转载:https://segmentfault.com/a/1190000005073746 Android通用流行框架大全 1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的 ...
- 【poj2122】 Optimal Milking
http://poj.org/problem?id=2112 (题目链接) 题意 有K个能挤M头奶牛的挤奶机和C头奶牛,告诉一些挤奶机和奶牛间距离,求最优分配方案使最大距离最小. Solution 先 ...
- Jenkins邮件配置,实现邮件发送策略(可实现每个Job对应不同的发送邮箱)
前言: 首先,要有一个用来发送的邮箱,首选网易!参考:http://www.cnblogs.com/EasonJim/p/6051636.html,这里我注册了网易的免费企业邮箱. 并且我新建没多个邮 ...
- Jenkins实现生产环境部署文件的回滚操作(Windows)
由于dotnet项目的生产环境环境部署工具比较少,所以我使用jenkins作为生产环境的自动化部署工具. 既然有回滚操作,那么就会有部署操作:要实现回滚,先要实现部署的操作,我在jenkins搭建了一 ...
- Xcopy命令参数
XCOPY是COPY的扩展,可以把指定的目录连文件和目录结构一并拷贝,但不能拷贝系统文件:使用时源盘符.源目标路径名.源文件名至少指定一个:选用/S时对源目录下及其子目录下的所有文件进行COPY.除非 ...
- 关于git的学习
Git是目前世界上最先进的分布式版本控制系统(没有之一)! 由于现在用的还不多,还没有这种体会,但是前人的经验是值得借鉴的,所以我认真的学习了一些关于git的简单操作,现在在这分享一些心得,或者说是为 ...
- 正则表达式——语法
正则表达式(regular expression)--描述一种字符串匹配模式,可以用来检测一个字符串是否包含特定的子串.用其他字符串将其代替.提取出某个符合要求的子串. 正则表达式 由普通字符 和 ...