首先,咱们通常被"执行上下文","执行上下文环境","上下文环境","执行上下文栈"这些名词搞混。那我们一一来揭秘这些名字的含义。

这一块一直比较晦涩难懂,还是需要仔细去斟酌斟酌。

什么是执行上下文(也叫做“执行上下文环境”,“上下文环境”)?

咱们还是先看代码。

console.log(a)  // undefined
var a = 100fn('bella')  // 'bella' 20
function fn(name) {age = 20console.log(name, age)var age
}console.log(b); // 这里报错
// Uncaught ReferenceError: b is not defined

第一个console输出 undefined,说明浏览器在执行console.log(a)的时候,已经知道a的存在的,但是不知道a的值。

第二个fn("bella")输出 "bella" 20,说明浏览器在执行的时候已经知道fn函数了,并且执行了

第三个console报错,b is noe defined。说明没有找到b

那么可以看出来,浏览器在执行之前做了一些准备工作。

那做了些什么准备工作:

  • 全局上下文环境: 变量定义,函数声明
  • 函数上下文环境(函数内部):变量定义,函数声明,this,arguments

下面这个例子很多地方都用来讲解执行上下文和上下文栈。

 1 // 这是一个压栈出栈的过程--执行上下文栈
 2 let a = 10; // 1、进入全局上下文环境
 3 let fn;
 4 let bar = function(x) {
 5     let b = 5
 6     fn(x + b) // 3、进入fn函数上下文环境
 7 };
 8 fn = function(y) {
 9     let c = 5
10     console.log(y + c)
11 }
12
13 bar(10) // 2、 进入bar函数上下文

这里引出了执行上下文栈的概念,上下文栈就是压栈和出栈的过程

1.在代码执行之前,首先创建全局上下文环境

    // 全局上下文环境
    a: undefinedfn: undefinedbar: undefined,    this: window

2.然后执行代码,在代码执行到12之前,全局上下文中的变量在执行中被赋值

    // 全局上下文环境a: 10fn: functionbar: function,    this: window

然后执行13行代码,调用bar函数,会创建一个新的执行上下文环境。并将这个bar上下文环境压栈,并设置为活动状态

   // bar函数上下文环境
    b: undefinedx: 10arguments: [10]    this: window

3.然后执行到第6行代码,调用fn的时候,会创建一个新的执行上下文。并将这个fn上下文环境压栈,并设置为活动状态。

// fn函数上下文环境
c: undefined
y: 15
arguments: [15]this: window

4.fn执行完毕后,调用fn函数生成的fn上下文环境出栈,销毁。然后bar出栈销毁。然后全局上下文出栈销毁

理解完了执行上下文,再看看this

相信都知道这句话,谁调用函数,this就指向谁。那么我们理解下this:

    var a = {name: 'A',fn: function() {console.log(this.name)}}a.fn() // this === a
    a.fn.call({name: 'B'}) // this === {name: 'B'}var fn1 = a.fnfn1() // this === window

this: this的值只有在执行的时候才能确认,定义的时候不能确认。因为this是执行上下文的一部分,而执行上下文需要再代码执行之前确定。

this执行会有不同,主要集中在这几个场景中:
  1. 作为构造函数执行,构造函数中
  2. 作为对象属性执行,上述代码中a.fn()
  3. 作为普通函数执行,上述代码中fn1()
  4. 用于call apply bind,上述代码中a.fn.call()

作用域

ES6之前没有块级作用域,除了全局作用域,函数会创建自己的作用域。
作用域在函数定义的时候已经确定了,不是在函数调用确定(区别于执行上下文环境,this是执行上下文环境中的)
作用域只是一个“地盘”,其中没有变量。变量是通过作用域对应的执行上下文环境中的变量对象来实现的。所以作用域是静态的,而执行上下文是动态的
有闭包存在的时候,一个作用域存在两个上下文环境也是有的。
也就是说,作用域只是用于划分你在这个作用域里面定义的变量的有效范围,出了这个范围就无效

作用域链

函数在定义的时候就确定了函数体内部自由变量的作用域
自由变量:比如a,在fn作用域使用,但是并没有在fn作用域定义。这就是自由变量
let a = 100
function fn() {let b = 20function bar() {console.log(a + b) // a是自由变量}return bar
}let x = fn(), b = 200
x()

那么自由变量是如何得到的?这就引出了作用域链
bar要取得a的值,就要在bar函数的作用域中取值,如果没有,就往上找,找到fn作用域内,也没有定义a,继续往上找,就找到全局作用域,找到就结束了。这就是作用域链
讲完这些,我们再通过一个例子来理解闭包
1 function F1() {
2     var a = 100
3     return function () {
4         console.log(a)
5     }
6 }
7 var f1 = F1()
8 var a = 200
9 f1()

自由变量将从作用域链中去寻找,但是 依据的是函数定义时的作用域链,而不是函数执行时,以上这个例子就是闭包。
怎么理解依据的是函数定义时的作用域链,而不是函数执行时这句话?
调用第9行之后
如果按照执行时,就输出的时200
但是作用域都是在定义时就生成了,所以f1回去再定义function的作用域去找,因此输出100.
理解闭包之后,我们就看看闭包的主要场景:
  • 函数作为返回值,上面的例子就是
  • 函数作为参数传递

转载于:https://www.cnblogs.com/thonrt/p/10333581.html

js - 执行上下文和作用域以及闭包相关推荐

  1. JavaScript执行上下文和作用域链

    执行上下文作用域链 执行上下文(Execution Context):函数执行前进行的准备工作(也称执行上下文环境) 运行 JavaScript 代码的时候,当代码执行进入一个环境时,就会为该环境创建 ...

  2. 2.JS执行上下文和变量对象

    文章目录 执行上下文栈 函数上下文 变量对象 执行过程 进入执行上下文 代码执行 两个例子 1 2   JS 是单线程语言,因此执行顺序是顺序执行,不过 JS 引擎在执行 JS 代码的时候并不是逐行执 ...

  3. 相学java_从这两套题,重新认识JS的this、作用域、闭包、对象

    日常开发中,我们经常用到this.例如用Jquery绑定事件时,this指向触发事件的DOM元素:编写Vue.React组件时,this指向组件本身.对于新手来说,常会用一种意会的感觉去判断this的 ...

  4. Javascript中你必须理解的执行上下文和调用栈

    执行上下文在 JavaScript 是非常重要的基础知识,想要理解 JavaScript 的执行过程,执行上下文是你必须要掌握的知识.否则只能是知其然不知其所以然. 理解执行上下文有什么好处呢? 它可 ...

  5. js执行环境作用域和闭包_JavaScript中执行上下文,提升,作用域和闭包的终极指南

    js执行环境作用域和闭包 It may seem surprising, but in my opinion the most important and fundamental concept to ...

  6. JS基础篇之作用域、执行上下文、this、闭包

    前言:JS 的作用域.执行上下文.this.闭包是老生常谈的话题,也是新手比较懵懂的知识点.当然即便你作为老手,也未必真的能理解透彻这些概念. 一.作用域和执行上下文 作用域: js中的作用域是词法作 ...

  7. js 预编译 解释执行 作用域链 闭包

    <script>var a,b = 1;function c(x){var aa = 2;function d(){var ab = 3;}}var d = function(){//.. ...

  8. 你不懂的JS学习笔记(作用域和闭包)

    You don't KnowJS 引语:你不懂的JS这本书github上已经有了7w的star最近也是张野大大给我推荐了一波,阅读过之后感觉对js的基础又有了更好的理解.本来我是从来不这种读书笔记的, ...

  9. 以及其任何超类对此上下文都是未知的_浏览器原理系列 - JS执行上下文详解(一):作用域

    本文主要介绍JS执行上下文相关的内容,理解了JavaScript的执行上下文才能更好地理解JavaScript语言本身以及该语言一些特性,如变量提升.作用域和闭包. 一.作用域 1.1 作用域 作用域 ...

最新文章

  1. R语言ggplot2包旋转(Rotate)可视化图像轴标签实战
  2. @程序员,什么键盘最耐用?| 每日趣闻
  3. php如何解决中文乱码问题?
  4. 简评file_get_contents与curl 效率及稳定性
  5. java 编译器获得型号_关于编译器构造:如何找到已编译类的目标Java版本?
  6. Unsatisfied dependency expressed through field 'service'
  7. SAS宏技术中,%let和call symput有什么区别?
  8. 【IntelliJ IDEA】使用idea解决新建jsp文件而找不到jsp文件模版的新建选项
  9. python windows 客户端开发_如何在Windows上使用Python进行开发
  10. 学习python的一些脚本
  11. VC6保姆级图文教程
  12. 生信技能树课程记录笔记(四)20220527
  13. 显著性检测论文梳理(Saliency Detection)
  14. 小米note3android8.0,小米Note3 lineage16 安卓9.0 极致省电 纯净 完美root Xposed 经典版...
  15. 支付宝小程序与生活号可互相关联啦!
  16. iOS UIFont 字体名字大全
  17. 如何平衡新老策略的好与坏,一道常见风控送命题解答
  18. Android SDK各个版本API的特性及兼容性(Dalvik/ART)
  19. Java中对中国标准时间进行格式化(yyyy-MM-dd HH:mm:ss)两种方法
  20. Android 开发的两种框架 MVC和MVP 的简单分析

热门文章

  1. springcloud 微服务鉴权_Java微服务框架spring cloud
  2. 微机原理实验8254计算机钢琴,GitHub - SincereXIA/PianoMFC: 西电微机原理课设项目,键盘电子乐器演奏程序设计(电子琴),MFC...
  3. android 没有指令,android – 运行时没有命令输出:’am start -n
  4. 测试jdbc连mysql数据库_java连接mysql数据库及测试是否连接成功的方法
  5. python pandas read_csv 迭代器使用方法_pandas.read_csv参数详解(小结)
  6. html 弹出加载页面,magnific popup:将整个html页面加载到弹出窗口中
  7. mysql5.7解压版错误_mysql 5.7 解压版 安装net start mysql 发生系统错误 2
  8. 无法开启计算机,Win7下鼠标右键无法开启计算机属性怎么办?
  9. php 获取警告信息,获取PHP警告错误信息的解决方法_PHP教程
  10. Linux网络编程 | socket选项设定 及 网络信息API