JS的作用域和作用域链
每个函数都有自己的作用域,当执行流进入一个函数时,函数就会被推入栈中,而在函数执行之后,栈将其执行环境弹出,把控制权放回给之前的作用域,全局作用域是最外围的一个作用域,因此,所有全局变量和函数都是作为window对象的属性和方法创建的。在某个方法函数的作用域中,所有代码执行完之后,该作用域被销毁,保存在其中的所有变量和函数定义也会随着被销毁,这就是局部作用域。
(PS:全局作用域直到应用程序退出,例如关闭网页活浏览器,才会被销毁。)
我个人理解的作用域链就是,当你声明一个函数时,局部作用域一级一级往上扣起来,就是作用域链。
如图:
作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
好了好了~ 书面语言终于说完了。我们还是来看看代码吧~
先来个基础点的:
var color = "blue";
function changeColor(){
var anothercolor = "red";
if(color==="blue"){
color = anothercolor;
}
//这里可以访问anothercolor,color }
//这里只可以访问color
changeColor();
console.log(color);//red
console.log(anothercolor);// undefined
解析:函数changeColor()的作用域链包含两个对象,它自己的变量对象和全局环境的变量对象。全局环境的变量对象(即window的对象)有color,changColor(),而changeColor()的变量对象是color,anothercolor。
(用我自己的话来解释就是:父级不能访问子级的变量,但是子级可以父级的变量,祖父的变量,曾祖父的变量......哈哈~。并且我们执行流的访问顺序也是从子级开始,一级一级往上查找你的需要的变量,最后一级就是全局变量。)
来看一下作用域链的典型栗子:
var x = 10; function foo(){ var y = 20; function bar(){
var z = 30; console.log(x+y+z);
}; bar(); }; foo();//60
解析:上面代码的输出结果是“60”,函数bar()可以直接访问"z",然后通过作用域链访问上层的“x”和“y”。
大概基本概念弄清楚了吧?!~~
那我要开始讲一些注意事情。。
JS没有块级作用域。
说明:在其他类C语言中,由{花括号}封闭的代码块都有自己的作用域,但是随和亲切的JS并非如此。
举个栗子:
if(true){
var color = "blue";
}
alert(color);//blue
解析:如果在C,C++,或JAVA中,color会在if语句执行完毕被销毁。但在JS中,if语句中的变量声明会将变量添加到当前的作用域(这里的全局环境)。
四不四觉得有点郁闷?怎么color这个变量还存在,不应该执行完之后,被销毁了吗?
一开始小编也是很郁闷,再想想JS的执行流,小编目前的理解是:JS一切皆对象,只有函数方法可以封装,也只有函数的执行需要被调用,所以每个函数方法都有自己的作用域,而像if和for循环等等,这些直接执行的引用函数,所定义的变量都会被添加在与它同兄弟级的作用域中。
现在再来看个栗子:
for(var i = 0 ; i < 10;i++){
doSomething(i);
}
alert(i);//10
解析:由for语句创建的变量i即使在for循环执行结束后,也依旧会存在于循环外部的执行环境中。
结合作用域看闭包
在JS中,闭包和作用域有紧密的关系。相信大家对下面的闭包栗子一定灰常熟悉,代码中通过闭包实现了一个简单的计算器。
function counter(){
var x = 0; return{
increase:function increase(){return ++x;},
decrease:function decrease(){return --x;}
};
} var ctor = counter(); console.log(ctor.increase());//1
console.log(ctor.decrease());//0
解析:四不四又纳闷了,怎么counter()函数退出了执行上下文栈,但是变量x还没有被销毁。闭包有三大特性:1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制回收。这里很明显,counter()函数利用闭包,把变量x引用到全局变量中。当var ctor = counter(),执行完毕后,ctor={increase:function(){...},decrease:function(){...}},这里需要注意的是,counter虽然退出了执行上下文栈,但是因为ctor中的成员仍然引用counter 的活动变量,所以counter的变量x依然在作用域中。
(附上个人对闭包的理解:在函数嵌套函数中,子函数获取父函数的私有变量,通过return引用到外部的作用域中。)
作用域链的主要作用就是用来变量查找,但是在JS中还有原型链的概念。
于是对于二维作用域链查找可以总结为:当代码需要查找一个属性或者描述符的时候,首先会通过作用域链来查找相关的对象,一旦对象被找到,就会根据对象的原型链来查找属性。
下面来举个栗子:
var foo = {}
function baz(){ Object.prototype.a = 'Set foo.a from prototype'; return function inner(){
console.log(foo.a);
}
}
baz()();//Set foo.a from prototype
解析:对于这个栗子,流程是这样的,在inner()并没有发现foo,就通过作用域链去baz查找,也没有在baz里面找到作用域链,就去到全局环境,找到了foo,但是并没有找到属性a,于是就去到了foo._proto_的原型链中找到了属性a,便输出该值。
文章说明:个人查看各种资料,原创所得,观点不一定准确,欢迎各路大牛勘误,小女子感激不尽。
JS的作用域和作用域链的更多相关文章
- 了解 JS 作用域与作用域链
(1)作用域 一个变量的作用域(scope)是程序源代码中定义的这个变量的区域. 1. 在JS中使用的是词法作用域(lexical scope) 不在任何函数内声明的变量(函数内省略var的也算全局) ...
- Js作用域与作用域链详解
一直对Js的作用域有点迷糊,今天偶然读到Javascript权威指南,立马被吸引住了,写的真不错.我看的是第六版本,相当的厚,大概1000多页,Js博大精深,要熟悉精通需要大毅力大功夫. 一:函数作用 ...
- Js作用域与作用域链详解[转]
一直对Js的作用域有点迷糊,今天偶然读到JavaScript权威指南,立马被吸引住了,写的真不错.我看的是第六版本,相当的厚,大概1000多页,Js博大精深,要熟悉精通需要大毅力大功夫. 一:函数作 ...
- js作用域与作用域链
一直对Js的作用域有点迷糊,今天偶然读到JavaScript权威指南,立马被吸引住了,写的真不错.我看的是第六版本,相当的厚,大概1000多页,Js博大精深,要熟悉精通需要大毅力大功夫. 一:函数作用 ...
- js学习--变量作用域和作用域链
作为一名菜鸟的我,每天学点的感觉还是不错的.今天学习闭包的过程中看到作用域与作用域链这两个概念,我觉得作为一名有追求的小白,有必要详细了解下. 变量的作用域 就js变量而言,有全局变量和局部变量.这里 ...
- JS -- The Scope Chain 作用域链
The Scope Chain JavaScript is a lexically scoped language: the scope of a variable can be thought of ...
- js 作用域,作用域链,闭包
什么是作用域? 作用域是一种规则,在代码编译阶段就确定了,规定了变量与函数的可被访问的范围.全局变量拥有全局作用域,局部变量则拥有局部作用域. js是一种没有块级作用域的语言(包括if.for等语句的 ...
- Js 作用域与作用域链与执行上下文不得不说的故事 ⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄
最近在研究Js,发现自己对作用域,作用域链,活动对象这几个概念,理解得不是很清楚,所以拜读了@田小计划大神的博客与其他文章,受益匪浅,写这篇随笔算是自己的读书笔记吧~. 作用域 首先明确一个概念,js ...
- 理解js中的作用域,作用域链以及闭包
作用域变量作用域的类型:全局变量和局部变量全局作用域对于最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的 <script> var outerVar = " ...
随机推荐
- Win7下Solr4.10.1和IK Analyzer中文分词
1.下载IK中文分词压缩包IK Analyzer 2012FF_hf1,并解压到D:\IK Analyzer 2012FF_hf1: 2.将D:\IK Analyzer 2012FF_hf1\IKAn ...
- django 学习 --- 环境搭建
1 安装django a: pip安装 pip install Django==版本号 b:源码安装 https://www.djangoproject.com/download/ tar -xvzf ...
- WordPress社会化评论插件多说、有言、灯鹭、评论啦
社会化登录是指网站的用户通过使用QQ.人人网.腾讯微博.新浪微博等社会化媒体账号登录该网站,并让用户能够使用社会化媒体账号进行允许的操作,如评论.分享等.经过简单的代码整合,社会化媒体账号可以在第三方 ...
- ecshop有关real_ip()你发现的问题
我这边有一个ECSHOP后台,有一个功能,在客户下订单时自动获取客户IP,用的是ECSHOP本身的real_ip函数,但这个函数存在一个问题,十个订单得到的IP,可能会有几个与CNZZ统计得到的不一样 ...
- 移动端app测试
对于手机项目(应用软件),主要是进行系统测试. 而针对手机应用软件的系统测试,我们通常从如下几个角度开展测试工作: 功能模块测试: 交叉事件测试: 性能测试: 安全测试: 容量测试: 兼容性测试: 接 ...
- C++ primer学习方法
C++ primer学习: 第一次可以跳着看.关键是要尽快用起来,在使用中熟练,而不是在细节中迷失. 以C++ Primer第五版为例,第一遍读的时候: Part1也就是前七章,除了6.6,6 ...
- Android 获取网络链接类型
/** * 获取当前网络类型 * @return 0:没有网络 1:WIFI网络 2:WAP网络 3:NET网络 */ public int getNetworkType() { int netTyp ...
- Basic Printing Architecture
https://blogs.technet.microsoft.com/askperf/2007/06/19/basic-printing-architecture/ Printer sharing, ...
- mkbundle(1) - Linux man page
mkbundle(1) - Linux man page Name mkbundle, mkbundle2 - Creates a bundled executable. Synopsis mkbun ...
- PHP PDO 安装使用
PDO(PHP Data Object) 是PHP 5新出来的东西,在PHP 6都要出来的时候,PHP 6只默认使用PDO来处理数据库,将把所有的数据库扩展移到了PECL,那么默认就是没有了我们喜爱的 ...