通过函数作用域和块级作用域看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不使用插件及swf实现无刷新文件上传
Dec 08 Javascript
javascript制作2048游戏
Mar 30 Javascript
jQuery实现的调整表格行tr上下顺序
Jan 10 Javascript
浅析JavaScript中的变量复制、参数传递和作用域链
Jan 13 Javascript
JavaScript实现通过select标签跳转网页的方法
Sep 29 Javascript
JS实现禁止鼠标右键的功能
Oct 15 Javascript
Angular ng-repeat指令实例以及扩展部分
Dec 26 Javascript
jQuery实现的分页功能示例
Jan 22 Javascript
Angularjs 1.3 中的$parse实例代码
Sep 14 Javascript
js中时间格式化的几种方法
Jul 22 Javascript
ES6 Generator基本使用方法示例
Jun 06 Javascript
JavaScript中数组去重的5种方法
Jul 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 intval的测试代码发现问题
2008/07/27 PHP
php实现微信公众号无限群发
2015/10/11 PHP
Joomla实现组件中弹出一个模式(modal)窗口的方法
2016/05/04 PHP
ThinkPHP表单令牌错误的相关解决方法分析
2016/05/20 PHP
laravel 去掉index.php伪静态的操作方法
2019/10/12 PHP
javascript的onchange事件与jQuery的change()方法比较
2009/09/28 Javascript
jQuery ajax cache缓存问题
2010/07/01 Javascript
单独使用CKFinder选择图片的方法
2010/08/21 Javascript
JS焦点图切换,上下翻转
2011/05/12 Javascript
全面理解面向对象的 JavaScript(来自ibm)
2013/11/10 Javascript
使用jquery中height()方法获取各种高度大全
2014/04/02 Javascript
jquery和js实现对div的隐藏和显示方法
2014/09/26 Javascript
javascript封装的sqlite操作类实例
2015/07/17 Javascript
AngularJS 指令详细介绍
2016/07/27 Javascript
jQuery下拉菜单的实现代码
2016/11/03 Javascript
angular-ui-sortable实现可拖拽排序列表
2016/12/28 Javascript
js判断手机号是否正确并返回的实现代码
2017/01/17 Javascript
手把手教你vue-cli单页到多页应用的方法
2018/05/31 Javascript
微信上传视频文件提示(推荐)
2018/11/22 Javascript
javascript实现函数柯里化与反柯里化过程解析
2019/10/08 Javascript
让mocha支持ES6模块的方法实现
2020/01/14 Javascript
vue 验证两次输入的密码是否一致的方法示例
2020/09/29 Javascript
[40:06]DOTA2亚洲邀请赛 4.3 突围赛 Liquid vs VGJ.T 第一场
2018/04/04 DOTA
python 打印对象的所有属性值的方法
2016/09/11 Python
用python写一个windows下的定时关机脚本(推荐)
2017/03/21 Python
Python实现嵌套列表及字典并按某一元素去重复功能示例
2017/11/30 Python
python语言中with as的用法使用详解
2018/02/23 Python
python tools实现视频的每一帧提取并保存
2020/03/20 Python
python中return如何写
2020/06/18 Python
Algenist奥杰尼官网:微藻抗衰老护肤品牌
2017/07/15 全球购物
Omio中国:全欧洲低价大巴、火车和航班搜索和比价
2018/08/09 全球购物
2014年冬季防火方案
2014/05/21 职场文书
新农村建设汇报材料
2014/08/15 职场文书
党员先进性教育整改措施
2014/09/18 职场文书
校长师德师风自我剖析材料
2014/09/29 职场文书
新闻发布会新闻稿
2015/07/17 职场文书