通过函数作用域和块级作用域看javascript的作用域链


Posted in Javascript onAugust 05, 2018

在ES6之前,javascript只有全局作用域和函数作用域。所谓作用域就是一个变量定义并能够被访问到的范围。也就是说如果一个变量定义在全局(window)上,那么在任何地方都能访问到这个变量,如果这个变量定义在函数内部,那么就只能在函数内部访问到这个变量。

全局作用域只要页面没关闭就会一直存在,而函数作用域只有在函数执行的时候才存在,执行完就销毁。且每次执行函数都会创建一个新的作用域。

那么什么是作用域链呢?
在了解作用域链之前,我们先了解一个执行期上下文的概念。

执行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象(即AO或GO),一个执行期上下文定义了一个函数的执行环境,函数每次执行时对应的执行期上下文都是独一无二的,所以每次调用一个函数都会创建一个新的执行期上下文,当函数执行完毕,所产生的执行期上下文被销毁。

作用域链就是函数中[[scope]]属性所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。

作用域链更像是一种包含的关系。比如说函数A内部定义了一个函数B,所以B的定义是依赖于A的,也就是说B在A的内部,那么B中就可以访问A的中的变量和方法。这种一层一层向上依赖的关系就构成了作用域链。

为了更好理解,我们直接看例子。

var name = 'xiaoyu';
function fn1() {};
function fn2() {
 var num = 10;
 function fn3() {
  var num1 = 10;
  console.log(num);
 };
 return fn3;
}
var fn4 = fn2();

通过函数作用域和块级作用域看javascript的作用域链

在上个例子我们知道,fn2执行的时候返回fn3,产生了闭包。但是一个函数执行然后返回另一个函数都会产生闭包嘛?我们来看一下。

var name = 'xiaoyu';
function fn1() {};
function fn2() {
 var num = 10;
 function fn3() {//fn3函数没有依赖fn2函数内的变量
  var num1 = 10;
  console.log(num1);
 };
 return fn3;
}
var fn4 = fn2();

通过函数作用域和块级作用域看javascript的作用域链

了解了作用域链之后,我们来看一个小例子,巩固一下。

var age = 10;
var obj = {
 age: 12,
 test: function() {
  console.log(age);
  console.log(obj.age);
  console.log(this.age);
 }
}
obj.test();

console.log(this.age)打印出12不难理解,但是为什么console.log(age)不也应该打印出12嘛。

我们说test执行时首先会在自己的作用域内查看有没有age变量,然后再沿着作用域链往上到全局作用域查找age变量,全局作用域下有age变量和data变量。所以console.log(age)打印出的10,如果要打印出12则需要访问obj.age。

ES6的块级作用域

在ES6之后,通过let和const引入了块级作用域。即通过let和const声明的变量只在声明所在的块级作用域内有效,并且let声明的变量虽然属于全局变量,但不再属于全局对象window。

我们通过一段代码来看一下引入块级作用域后,函数的作用域链的变化。

var age = 10;
let obj = {
 age: 12,
 test: function() {
   console.log(age);
   console.log(obj.age);
   console.log(this.age);
 }
}
obj.test();

通过函数作用域和块级作用域看javascript的作用域链

Javascript 相关文章推荐
Jquery AJAX 框架的使用方法
Nov 03 Javascript
基于jquery的loading 加载提示效果实现代码
Sep 01 Javascript
js+HTML5基于过滤器从摄像头中捕获视频的方法
Jun 16 Javascript
JavaScript中数据结构与算法(五):经典KMP算法
Jun 19 Javascript
关于vuex的学习实践笔记
Apr 05 Javascript
Bootstrap弹出框(Popover)被挤压的问题小结
Jul 11 Javascript
Three.js利用性能插件stats实现性能监听的方法
Sep 25 Javascript
详解ESLint在Vue中的使用小结
Oct 15 Javascript
JavaScript实现的鼠标跟随特效示例【2则实例】
Dec 22 Javascript
巧妙运用v-model实现父子组件传值的方法示例
Apr 07 Javascript
js基础之事件捕获与冒泡原理
Oct 09 Javascript
vue中使用极验验证码的方法(附demo)
Dec 04 Javascript
vue实现简单的MVVM框架
Aug 05 #Javascript
使用D3.js+Vue实现一个简单的柱形图
Aug 05 #Javascript
详解Require.js与Sea.js的区别
Aug 05 #Javascript
vue中关闭eslint的方法分析
Aug 04 #Javascript
详解Vue取消eslint语法限制
Aug 04 #Javascript
JavaScript原型对象、构造函数和实例对象功能与用法详解
Aug 04 #Javascript
JavaScript中变量、指针和引用功能与操作示例
Aug 04 #Javascript
You might like
php中检查文件或目录是否存在的代码小结
2012/10/22 PHP
php单态设计模式(单例模式)实例
2014/11/18 PHP
php轻量级的性能分析工具xhprof的安装使用
2015/08/12 PHP
php 伪造HTTP_REFERER页面URL来源的三种方法
2016/09/22 PHP
Yii实现复选框批量操作实例代码
2017/03/15 PHP
PHP实现的DES加密解密封装类完整实例
2017/04/29 PHP
jQuery对象与DOM对象之间的转换方法
2010/04/15 Javascript
javascript 得到变量类型的函数
2010/05/19 Javascript
ExtJs Excel导出并下载IIS服务器端遇到的问题
2011/09/16 Javascript
子页向父页传值示例
2013/11/27 Javascript
jQuery实现可高亮显示的二级CSS菜单效果
2015/09/01 Javascript
ES6实现的遍历目录函数示例
2017/04/07 Javascript
vue组件的写法汇总
2018/04/12 Javascript
vue路由 遍历生成复数router-link的例子
2019/10/30 Javascript
NodeJS http模块用法示例【创建web服务器/客户端】
2019/11/05 NodeJs
JS对象属性的检测与获取操作实例分析
2020/03/17 Javascript
[02:59]DOTA2完美大师赛主赛事第三日精彩集锦
2017/11/25 DOTA
[01:01:14]完美世界DOTA2联赛PWL S2 SZ vs Rebirth 第一场 11.21
2020/11/23 DOTA
Python使用Phantomjs截屏网页的方法
2018/05/17 Python
matplotlib实现热成像图colorbar和极坐标图的方法
2018/12/13 Python
详解python中的生成器、迭代器、闭包、装饰器
2019/08/22 Python
纯CSS3制作页面切换效果的实例代码
2019/05/30 HTML / CSS
Coggles美国/加拿大:高级国际时装零售商
2018/10/23 全球购物
十八大闭幕感言
2014/01/22 职场文书
幼儿园元旦活动感言
2014/03/02 职场文书
保护动物倡议书
2014/04/15 职场文书
我的教育故事演讲稿
2014/05/04 职场文书
自荐信格式范文
2015/03/04 职场文书
2015年119消防宣传日活动总结
2015/03/24 职场文书
车间安全生产管理制度
2015/08/06 职场文书
校运会广播稿
2015/08/19 职场文书
实习报告范文之电话客服岗位
2019/07/26 职场文书
创业计划书之珠宝饰品
2019/08/26 职场文书
mybatis使用oracle进行添加数据的方法
2021/04/27 Oracle
详解盒子端CSS动画性能提升
2021/05/24 HTML / CSS
MySQL中连接查询和子查询的问题
2021/09/04 MySQL