一 : 作用域的相关概念

首先看下 变量作用域 的概念:一个变量的作用域是程序源代码中定义这个变量的区域。————————《javascript权威指南》第六版
全局变量拥有全局作用域,函数体内定义的局部变量拥有函数作用域。

就个人理解,作用域(scope),顾名思义,是一块区域领域 ,并且有某些对象(包括变量,属性,方法等)能够在这里起作用;作用域是在定义的时候决定的,和什么时候执行无关;这时候问题来了:

问题1:区域在那儿?

他是一个概念,是看不到摸不着的;在这个区域内原本是什么都没有的,但是与作用域密切相关的一个概念  执行上下文(EC),他却是与作用域相呼应,哪些变量、参数、this值等统统的会保存在上下文中(上下文是一个对象,变量参数等作为他的属性保存);全局作用域 对应 全局执行上下文,函数作用域 对应相应的 函数执行上下文; 而上下文是在代码执行的时候产生的,他保存在内存中,这个上下文中的变量等 则属于 其相对应的作用域(全局作用域或函数作用域);详见下一节【执行上下文】。

问题1:某些对象是谁?
这块区域中定义了谁,对象就有谁。全局作用域中定义了变量a和声明了函数 fun,那么a和fun就在全局作用域中起作用;fun域中定义了变量m ,则m 就在fun域中起作用(这时候变量a 也是起作用的,原理可查看后面作用域链 概念);另外还有this值,当前函数参数;主要就包含这三类对象。

问题2:这些对象啥时候起作用?

执行时,指全局函数执行时,生成执行上下文,变量等起作用;局部函数执行时,生成函数执行上下文,函数体内变量等起作用;详细查看 执行上下文。

js变量具有 的 向下透明 和 向上封闭 特性,向下透明,指fun,fn可以在当前作用域访问全局变量a,fn可以访问a,m,但在函数体内,局部变量的优先级高于同名上级变量。 向上封闭,指全局作用域 不可以访问 fun域中的变量m,更不可以访问 fn中的变量n,fun作用域也不可以访问他内部嵌套的fn域中变量n;还涉及到的一个概念就是 作用域链(scope chain):是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量。

当全局作用域中没有函数定义时,作用域链上就只有一个对象,全局对象,这个对象定义了相关的变量信息;一般所谓链,都是指多个穿起来才叫链,这儿比较特殊,是只有一个元素的链。

当全局作用域中包含多个嵌套函数时,随着函数一级一级执行展开,作用域链将会变成由多个对象组成的链表;这个链表是动态的,随着代码的执行而不停的增加和释放内存。

上图可见,向下透明,向上封闭的原理,例如b变量保存的值是一个指针,那么在a域内,大家能看到的就是这个指针值,而不能看到b域内的变量,因此 b域 相对于a域是封闭的,也就是向上封闭;说到这儿,是不是感觉有点和闭包相似呢,闭包就是封闭的,只留一个接口(等同于a)给外界,包里都有啥不让别人直接看见。js之所以会出现闭包,可能就是因为这种存储机制造成的——变量保存为引用类型!闭包就是这样,但凡函数返回值是引用类型,都会产生闭包。

js是基于 词法作用域  的语言:通过阅读包含变量定义在内的数行源码,就能知道变量的作用域。

二 :作用域的分类

作用域 可分为两种,全局作用域函数作用域;函数作用域是由函数创建的,至于全局作用域,我们也可以将全局作用域当作是 window函数 创建的,并且这个函数只有一个,而我们所写的所有代码都在这个函数之内。所以总结一句话:只有 函数 才能创建作用域  

引申:这个全局函数 和 pareInt()等全局函数是什么关系呢?

默全局作用域从代码运行开始就一直存在着;

函数作用域:

变量在声明他们的函数体以及这个函数体内嵌套的任意函数体内都是有定义的。
在函数内声明的所有的变量在函数体内始终是可见的。                                                                    
                                                                                                                     -------------《javascript权威指南》第六版

三个要点:所有变量    始终可见、都有定义

1、所有变量  ————    函数参数  +  函数体变量+  for循环/if 语句/while语句 变量

如上图中所标出的所有变量,都 属于当前 函数作用域,这些变量向下透明,而向上封闭,既fn2函数体内可以访问fun函数以及全局变量,但是全局和fun却不能直接访问fn2中的变量。

注:一段带有大括号的代码,经常会被称为 代码块;而这种称呼,在Js中可能会带来误解;JS中 没有 块级作用域 ,这个概念与其他编程语言(如C等), 是不一样的;如果一定要用代码块来理解的话,js 只识别 全局代码块 和 函数代码块 当作其作用域。

例如下C++代码:

void fun(int x){
int a; //变量a的作用域在函数fun中
for(int i=;i<=;i++){i++} //变量i在块级作用域 for 代码块中
}

  

2、始终可见—————— 指变量在书写 声明源代码 之前已经可用

js中声明包含两种声明 变量声明(var) 和 函数声明 (function);变量声明时,只定义了变量名,类型不确定;函数声明时,将函数名当作变量名,类型是函数。

这个特性被称为 声明提前 ,即当前函数体内的声明所有变量(不涉及赋值)代码,都被提前到函数体顶部;通俗的说,就是指只要是在函数体内声明了变量,不论代码写在了什么位置,在函数体内的任意位置都可以访问到。事实上这和Js引擎规定如何执行代码顺序有关,他会先查找有关声明的关键词var 和 function 来保存在执行上下文中,这个工作是在 形成执行上下文 的初始化阶段 完成的,而赋值则是在

举例,执行如下代码:

function fn(){
console.log(a); //underfined
var a=3;
}
fn(); 

等同于下面代码:

function fn(){
var a; //变量声明提前
console.log(a); //变量已声明未赋值时默认值是underfined
a=3;
}
fn();

引申疑问:声明提前 这步工作 是在什么时候做的呢?

这就涉及到了另外一个概念,执行上下文环境 ,变量/函数的声明 工作都是在 代码执行的时候才做的;

例如 文件运行开始,就生成了 全局执行上下文环境,这个环境的生成分为两个阶段完成,分别是 初始化阶段 +  赋值阶段 ,那么声明提前 就包含在 初始化阶段中。详情见下一节。

 3、都有定义—————— 变量在当前函数体内有定义

根据定义,变量在声明他们的函数体以及这个函数体内嵌套的任意函数体内都是有定义的,可见,函数体内不论包括啥函数,包括多少层函数,当前函数体内定义的变量一直在众多嵌套函数中是有效可用的;也就是上面提到的向下透明特性。

JS函数——作用域的更多相关文章

  1. JS 函数作用域及变量提升那些事!

    虽然看了多次js函数作用域及变量提升的理论知识,但小编也是一知半解~ 这几天做了几道js小题,对这部分进行了从新的理解,还是有所收获的~ 主要参考书籍: <你不知道的JavaScript(上卷) ...

  2. 深入理解JS函数作用域链与闭包问题

    function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } ); a.fun(); a.f ...

  3. JS函数作用域及作用域链理解

    从事web开发工作,尤其主要是做服务器端开发的,难免会对客户端语言JavaScript一些概念有些似懂非懂的,甚至仅停留在实现功能的层面上,接下来的文章,是记录我对JavaScript的一些概念的理解 ...

  4. js 函数 作用域 全局作用域 局部作用域 闭包

    一个变量没有声明但调用 直接报错,声明没有赋值会显示未定义. 作用域 作用域(scope):一条数据可以在哪个范围中使用. 通常来说,一段程序代码中所用到的数据并不总是有效/可用的,而限定这个数据的可 ...

  5. js函数作用域

    函数 1.函数没有用return返回函数时,返回默认参数undefined 结果 return返回得话 就是里面得数值 结果 JS执行过程是上到下,下面的a元素覆盖了上面的a元素 function d ...

  6. JS _函数作用域及变量提升

    虽然看了多次js函数作用域及变量提升的理论知识,但也是一知半解~ 这几天做了几道js小题,对这部分进行了从新的理解,还是有所收获的~ 主要参考书籍: <你不知道的JavaScript(上卷)&g ...

  7. js 碎片整理(变量声明,函数作用域)

    1.变量声明: 在非严格模式下,函数可以对未声明的变量赋值,而这样赋值的结果就是该变量就会变成全局变量. (function(){ var a = 1; })(); console.log(a) ; ...

  8. 在iframe里调用parent.func()引出的js函数运行在它们被定义的作用域里,而不是它们被执行的作用域里

    有个document里定义了一个函数func(),同时在document里嵌入了一个iframe,在这个iframe里调用父窗口的方法:parent.func(),本来我以为这个函数的运行环境是在这个 ...

  9. 读书笔记-你不知道的JS上-函数作用域与块作用域

    函数作用域 Javascript具有基于函数的作用域,每声明一个函数,都会产生一个对应的作用域. //全局作用域包含f1 function f1(a) { var b = 1; //f1作用域包含a, ...

随机推荐

  1. 用maven骨架生成项目速度慢的问题

    最近从IntelliJ Idea 14的Community版本切换到Ultimate. 问题出现 最近从IntelliJ Idea 14的Community版本切换到Ultimate,key是从网络上 ...

  2. JS获取request字符串

    function getQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&] ...

  3. 使用react-native做一个简单的应用-01项目介绍

    学习react-native也有一个月的时间了.当学习了关于react-native的基础知识之后,打算自己去仿一个应用去练手.于是花了10天左右的时间,这个小应用的基本功能也实现的差不多了. 在展示 ...

  4. Tomcat地址栏传中文参数乱码问题处理

    javascript中有时需要向后台传递中文参数,再次展示到前台时显示为乱码,解决方案: 方案1:修改Tomcat-conf-server.xml文件 大约69-71行  修改为: <Conne ...

  5. 计算两个集合的交集数字(java)

    循环判断2个数组 将相同的公共元素复制到新数组中即可 import java.util.Arrays; public class count_same_number { public static i ...

  6. 仅当使用了列的列表 并且 identity_insert 为 on 时 才能在表 中为标识列指定显式值

    当 IDENTITY_INSERT 设置为 OFF 时,不能向表 'products' 中的标识列插入显式值.” 示例: 1.首先建立一个有标识列的表:CREATE TABLE products (i ...

  7. Spring-----6、Spring3.0提供的Java配置管理

    转载自:http://blog.csdn.net/hekewangzi/article/details/45646279

  8. MySQL实用基础笔记

    /* 启动MySQL */ net start mysql /* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码 /* 跳过权限验证登录MySQL */ mysq ...

  9. ecshop简单结构

    Ecshop包括的文件夹有admin.api.cert.data.images.includes.js. languages.plugins.temp.theme.wap.widget这些文件夹,和根 ...

  10. Python学习笔记(六)Python的列表生成式、生成器

    列表生成式 List Comprehensions 列表生成式是Python内置的非常简单却强大的可以用来创建list的生成式. 简单的数值范围的list可以使用一下方式生成: >>> ...