轻松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 相关文章推荐
Javascript实现带关闭按钮的网页漂浮广告代码
Jan 12 Javascript
父节点获取子节点的字符串示例代码
Feb 26 Javascript
js实现点击图片将图片地址复制到粘贴板的方法
Feb 16 Javascript
JavaScript中的Math.LN2属性用法详解
Jun 12 Javascript
JS判断当前页面是否在微信浏览器打开的方法
Dec 08 Javascript
jquery插件uploadify多图上传功能实现代码
Aug 12 Javascript
详解用node搭建简单的静态资源管理器
Aug 09 Javascript
fetch 使用及如何接收JS传值
Nov 11 Javascript
js中el表达式的使用和非空判断方法
Mar 28 Javascript
vue实现选项卡及选项卡切换效果
Apr 24 Javascript
vue-cli V3.0版本的使用详解
Oct 24 Javascript
解决nuxt页面中mounted、created、watch执行两遍的问题
Nov 05 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
中东人咖啡哲学
2021/03/03 咖啡文化
相对路径转化成绝对路径
2007/04/10 PHP
Drupal 添加模块出现莫名其妙的错误的解决方法(往往出现在模块较多时)
2011/04/18 PHP
PHP 年龄计算函数(精确到天)
2012/06/07 PHP
PHP反射类ReflectionClass和ReflectionObject的使用方法
2013/11/13 PHP
PHP+JS实现大规模数据提交的方法
2015/07/02 PHP
详解PHP 二维数组排序保持键名不变
2019/03/06 PHP
解决Laravel 不能创建 migration 的问题
2019/10/09 PHP
(JS实现)MapBar中坐标的加密和解密的脚本
2007/05/16 Javascript
javascript类继承机制的原理分析
2009/09/12 Javascript
JQuery的read函数与js的onload不同方式实现
2013/03/18 Javascript
js弹出确认是否删除对话框
2014/03/27 Javascript
JavaScript中的依赖注入详解
2015/03/18 Javascript
Jquery1.9.1源码分析系列(十五)动画处理之外篇
2015/12/04 Javascript
jQuery滚动新闻实现代码
2016/06/26 Javascript
jQuery 常见小例汇总
2016/12/14 Javascript
JS去除重复并统计数量的实现方法
2016/12/15 Javascript
JavaScript数据结构与算法之二叉树插入节点、生成二叉树示例
2019/02/21 Javascript
微信小程序学习笔记之表单提交与PHP后台数据交互处理图文详解
2019/03/28 Javascript
vue实现绑定事件的方法实例代码详解
2019/06/20 Javascript
[59:00]DOTA2-DPC中国联赛 正赛 Ehome vs PSG.LGD BO3 第一场 3月7日
2021/03/11 DOTA
Python 统计字数的思路详解
2018/05/08 Python
解决pip install的时候报错timed out的问题
2018/06/12 Python
python针对不定分隔符切割提取字符串的方法
2018/10/26 Python
如何使用Python多线程测试并发漏洞
2019/12/18 Python
韩国家庭购物网上商店:Nsmall
2017/05/07 全球购物
Anthropologie英国:美国家喻户晓的休闲服装和家居产品品牌
2018/12/05 全球购物
ESDlife健康生活易:身体检查预订、搜寻及比较
2019/05/10 全球购物
瑞士网球商店:Tennis-Point
2020/03/12 全球购物
.net软件工程师应聘上机试题
2015/03/10 面试题
学生会离职感言
2014/02/11 职场文书
公司承诺书格式
2014/05/21 职场文书
法人授权委托书公证范本
2014/09/14 职场文书
群众路线对照检查剖析材料
2014/10/09 职场文书
2015年三年级班主任工作总结
2015/05/21 职场文书
uniapp 微信小程序 自定义tabBar 导航
2022/04/22 Javascript