轻松5句话解决JavaScript的作用域


Posted in Javascript onJuly 15, 2016

javascript 程序的每一个字节都是在这个或那个运行上下文(execution context)中执行的。你可以把这些上下文想象为代码的邻居,它们可以给每一行代码指明:从何处来,朋友和邻居又是谁。没错,这是很重要的信息,因为 javascript社会有相当严格的规则,规定谁可以跟谁交往。运行上下文则是有大门把守的社区而非其内开放的小门。

我们通常可以把这些社会边界称为作用域,并且有充足的重要性在每一位邻居的宪章里立法,而这个宪章就是我们要说的上下文的作用域链(scope chain)。在特定的邻里关系内,代码只能访问它的作用域链内的变量。与超出它邻里的变量比起来,代码更喜欢跟本地(local,即局部)的打交道。

任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,轻松搞定JavaScript作用域

一、“JavaScript中无块级作用域”

在Java或C#中存在块级作用域,即:大括号也是一个作用域。

public static void main ()
{ if(1==1){
 String name = "seven";
 }
 System.out.println(name);
}// 报错
public static void Main()
{ if(1==1){
 string name = "seven";
 }
 Console.WriteLine(name);
}// 报错

在JavaScript语言中无块级作用域

function Main(){
 if(1==1){
 var name = 'seven';
 }
 console.log(name);
}// 输出: seven

二、JavaScript采用函数作用域

在JavaScript中每个函数作为一个作用域,在外部无法访问内部作用域中的变量。

function Main(){
 var innerValue = 'seven';
}
 
Main();
 
console.log(innerValue);
 
// 报错:Uncaught ReferenceError: innerValue is not defined

三、JavaScript的作用域链

由于JavaScript中的每个函数作为一个作用域,如果出现函数嵌套函数,则就会出现作用域链。

xo = 'alex';
 
function Func(){
 var xo = "seven";
 function inner(){
 var xo = 'alvin';
 console.log(xo);
 }
 inner();
}
Func();

如上述代码则出现三个作用域组成的作用域链,如果出现作用域链后,那么寻找变量时候就会出现顺序,对于上述实例:

当执行console.log(xo)时,其寻找顺序为根据作用域链从内到外的优先级寻找,如果内层没有就逐步向上找,直到没找到抛出异常。

轻松5句话解决JavaScript的作用域

四、JavaScript的作用域链执行前已创建

JavaScript的作用域在被执行之前已经创建,日后再去执行时只需要按照作用域链去寻找即可。

示例一:

xo = 'alex';
 
function Func(){
 var xo = "seven";
 function inner(){
 
 console.log(xo);
 }
 return inner;
}
 
var ret = Func();
ret();
// 输出结果: seven

上述代码,在函数被调用之前作用域链已经存在:

全局作用域 -> Func函数作用域 -> inner函数作用域
当执行【ret();】时,由于其代指的是inner函数,此函数的作用域链在执行之前已经被定义为:全局作用域 -> Func函数作用域 -> inner函数作用域,所以,在执行【ret();】时,会根据已经存在的作用域链去寻找变量。

示例二:

xo = 'alex';
 
function Func(){
 var xo = "eirc";
 function inner(){
 
 console.log(xo);
 }
 xo = 'seven';
 return inner;
}
 
var ret = Func();
ret();
// 输出结果: seven

上述代码和示例一的目的相同,也是强调在函数被调用之前作用域链已经存在:

全局作用域 -> Func函数作用域 -> inner函数作用域
不同的时,在执行【var ret = Func();】时,Func作用域中的xo变量的值已经由 “eric” 被重置为 “seven”,所以之后再执行【ret();】时,就只能找到“seven”。

示例三:

xo = 'alex';
function Bar(){
 console.log(xo);
}
 
function Func(){
 var xo = "seven";
 
 return Bar;
}
 
var ret = Func();
ret();
// 输出结果: alex

上述代码,在函数被执行之前已经创建了两条作用域链:

全局作用域 -> Bar函数作用域
全局作用域 -> Func函数作用域
当执行【ret();】时,ret代指的Bar函数,而Bar函数的作用域链已经存在:全局作用域 -> Bar函数作用域,所以,执行时会根据已经存在的作用域链去寻找。

五、声明提前

在JavaScript中如果不创建变量,直接去使用,则报错:

console.log(xxoo);
// 报错:Uncaught ReferenceError: xxoo is not defined

JavaScript中如果创建值而不赋值,则该值为 undefined,如:

var xxoo;
console.log(xxoo);
// 输出:undefined
在函数内如果这么写:
function Foo(){
 console.log(xo);
 var xo = 'seven';
}
 
Foo();
// 输出:undefined

上述代码,不报错而是输出 undefined,其原因是:JavaScript的函数在被执行之前,会将其中的变量全部声明,而不赋值。所以,相当于上述实例中,函数在“预编译”时,已经执行了var xo;所以上述代码中输出的是undefined。

Js是一门很有趣的语言,由于它的很多特性是针对HTML中DOM的操作,因而显得随意而略失严谨,但随着前端的不断繁荣发展和Node的兴起,Js已经不再是"toy language"或是jQuery时代的"CSS扩展",本文提到的这些无论是对新手还是从传统Web开发中过度过来的Js开发人员来说,都很容易被混淆或误解,希望本文可以有所帮助。

Javascript 相关文章推荐
一个可以显示阴历的JS代码
Mar 05 Javascript
js编码、解码函数介绍及其使用示例
Sep 05 Javascript
jQuery图片轮播的具体实现
Sep 11 Javascript
打造自己的jQuery插件入门教程
Sep 23 Javascript
使用JS正则表达式 替换括号,尖括号等
Nov 29 Javascript
JS实现获取图片大小和预览的方法完整实例【兼容IE和其它浏览器】
Apr 24 Javascript
JavaScript之promise_动力节点Java学院整理
Jul 03 Javascript
vue-router配合ElementUI实现导航的实例
Feb 11 Javascript
React中嵌套组件与被嵌套组件的通信过程
Jul 11 Javascript
node中实现删除目录的几种方法
Jun 24 Javascript
layui表格内容溢出的解决方法
Sep 06 Javascript
node.js通过Sequelize 连接MySQL的方法
Dec 28 Javascript
jQuery EasyUI基础教程之EasyUI常用组件(推荐)
Jul 15 #Javascript
IE下JS保存图片的简单实例
Jul 15 #Javascript
jQuery 3.0中存在问题及解决办法
Jul 15 #Javascript
JavaScript6 let 新语法优势介绍
Jul 15 #Javascript
简单实现轮播图效果的实例
Jul 15 #Javascript
浅谈javascript运算符——条件,逗号,赋值,()和void运算符
Jul 15 #Javascript
JavaScript计算器网页版实现代码分享
Jul 15 #Javascript
You might like
PHP n个不重复的随机数生成代码
2009/06/23 PHP
php7基于递归实现删除空文件夹的方法示例
2017/06/15 PHP
PHP生成短网址的思路以及实现方法的详解
2019/03/25 PHP
javascript 解决表单仍然提交即使监听处理函数返回false
2010/03/14 Javascript
javascript实现平滑无缝滚动
2020/08/09 Javascript
jquery插件锦集【推荐】
2016/12/16 Javascript
jQuery实现文章图片弹出放大效果
2017/04/06 jQuery
vue过渡和animate.css结合使用详解
2017/06/14 Javascript
Vue自动构建发布脚本的方法示例
2020/07/24 Javascript
js实现无缝轮播图插件封装
2020/07/31 Javascript
jquery实现加载更多"转圈圈"效果(示例代码)
2020/11/09 jQuery
在Gnumeric下使用Python脚本操作表格的教程
2015/04/14 Python
粗略分析Python中的内存泄漏
2015/04/23 Python
Swift中的协议(protocol)学习教程
2016/07/08 Python
利用Python查看目录中的文件示例详解
2017/08/28 Python
Python命令行解析模块详解
2018/02/01 Python
Python如何抓取天猫商品详细信息及交易记录
2018/02/23 Python
Python使用matplotlib绘制多个图形单独显示的方法示例
2018/03/14 Python
python ---lambda匿名函数介绍
2019/03/13 Python
Puppeteer使用示例详解
2019/06/20 Python
python pandas模块基础学习详解
2019/07/03 Python
Python中的整除和取模实例
2020/06/03 Python
Python自省及反射原理实例详解
2020/07/06 Python
Python如何给函数库增加日志功能
2020/08/04 Python
python多线程爬取西刺代理的示例代码
2021/01/30 Python
CSS3使用border-radius属性制作圆角
2014/12/22 HTML / CSS
阿联酋团购网站:Groupon阿联酋
2016/10/14 全球购物
下面这个程序执行后会有什么错误或者效果
2014/11/03 面试题
飞利信loadrunner和软件测试笔试题
2012/09/22 面试题
体育教育个人自荐信范文
2013/12/01 职场文书
房地产公司见习自我鉴定
2014/04/28 职场文书
就职演讲稿范文
2014/05/19 职场文书
2014年培训工作总结范文
2014/11/27 职场文书
2015年元旦促销方案书
2014/12/09 职场文书
教师节慰问信
2015/02/15 职场文书
2015医德医风个人工作总结
2015/04/02 职场文书