IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 【修炼JavaScript】javascript中的作用域和执行上下文 -> 正文阅读

[JavaScript知识库]【修炼JavaScript】javascript中的作用域和执行上下文

前言

本文将采用尽量简洁清晰的语言来讲清楚javascript中的作用域和执行上下文,读完本文能够学习到一下知识点:

  • 作用域分为词法作用域和动态作用域,javascript属于哪一种?
  • 词法作用域也叫静态作用域,它和动态作用域有什么区别?
  • 作用域实在哪个阶段确定的?它的作用是什么?
  • 执行上下文分为哪几类?什么时候会创建执行上下文?
  • 如何管理众多的执行上下文?

带着这些疑问,让我们开始本文的阅读吧!

作用域

作用域是指程序源代码中定义变量的区域。

它规定了查找变量的规则以及当前代码对变量的访问权限。

javascript的作用域是词法作用域,也叫静态作用域。


词法作用域和动态作用域

词法作用域的英文名称是 L e x i c a l S c o p e Lexical Scope LexicalScope L e x i c a l Lexical Lexical的意思就是词法。

为什么叫做词法作用域呢?因为该作用域规则是在编译器进行代码编译时确定的。

编译器在进行代码编译时主要有三个阶段:

  • 词法分析(Tokenizing | Lexing)
  • 语法分析生成抽象语法树(Parsing)
  • 代码生成(Code Generation)

关于更多编译器原理参考Anatomy of a Compiler

💥静态作用域:在代码编译阶段或者说函数定义时确定,javascript的作用域属于这一种。

💥动态作用域:在函数调用时确定。

来看一个例子就能明白它们的区别了。

var name = 'William'

function bar(){
	console.log(name)
}

function foo(){
	var name = 'Jane'
	bar()
}

foo()	// 打印结果为'William'

解释: bar函数执行时,发现console.log(name),首先查找自己函数内部有没有name,发现没有,于是再根据书写位置查找上一层,发现name,于是就输出了William

那么如果是动态作用域又会是怎样的呢?执行bar发现当前作用域没有name,于是到调用函数的上一层也就是foo里寻找,于是输出Jane

执行上下文

学习javascript变量的时候,我们经常都会听到变量提升,那么变量提升发生在什么时候呢?别急,往下看。

javascript引擎在执行一段可执行代码(executable code)时是一段一段执行的,而不是一行一行执行。看下面例子:

var bar = function () {
	console.log('bar1')
}

bar() // bar1

var bar = function () {
	console.log('bar2')
}

bar() // bar2
function bar(){
  console.log('bar1');
}

bar() // bar2

function bar(){
  console.log('bar2');
}

bar() // bar2

可以看到,如果是代码是一行一行往下执行,那么第二个例子中第一个bar()结果应该是bar1,然而它却打印出了bar2

那么javascript是如何把代码划分成段的呢?首先我们得清楚Javascript中的可执行代码有哪一些?

javascript中的可执行代码

分为三类:

  • 全局代码
  • 函数代码
  • eval代码

当执行遇到函数时,就会来划分一段代码,这里的一段具体来说就是我们所说的执行上下文,一个执行上下文的生命周期分为两个阶段:

  • 创建阶段
  • 执行阶段

在创建阶段会做很多的准备工作,包括变量提升,作用域链的确定,确定this指向等工作,具体的准备工作我们以后再说,这里先记住,执行上下文是在函数调用时创建的。

我们先弄清楚执行上下文是如何管理的。

执行上下文栈

对于一个源代码程序,没调用一个函数就会创建一个执行上下文,这些执行上下文统一使用一个执行上下文栈来管理,用一个例子来讲一下其运行机制:

function foo1() {
	var name = 'William'
	console.log(name)
}

function foo2() {
	foo1()
}

function foo3() {
	foo2()
}

foo3()

我们使用一个数组ContextStack来模拟栈,执行代码时最先遇到全局上下文globalContext,将其入栈

ContextStack = [
	globalContext
]

然后代码往下执行,遇到函数调用foo3(),于是创建了一个foo3函数的执行上下文,将其入栈

ContextStack.push(<foo3> functionContext)

/*
ContextStack = [
	globalContext,
	<foo3> functionContext
]
*/

发现foo3还调用了foo2

ContextStack.push(<foo2> functionContext)

/*
ContextStack = [
	globalContext,
	<foo3> functionContext
	<foo2> functionContext
]
*/

foo2居然还调用了foo1:

ContextStack.push(<foo1> functionContext)

/*
ContextStack = [
	globalContext,
	<foo3> functionContext
	<foo2> functionContext
	<foo1> functionContext
]
*/

foo1执行,打印William,执行完毕,将它的上下文出栈,其他函数紧接着执行完毕,依次出栈:

ContextStack.pop()
ContextStack.pop()
ContextStack.pop()

/*
ContextStack = [
	globalContext
]
*/

整个应用程序执行完毕时globalContext才会出栈,否则会一直作为栈底元素。

总结

总结部分就来简短回答一下前言中的问题:

1??作用域分为词法作用域和动态作用域,javascript属于哪一种?
2??词法作用域也叫静态作用域,它和动态作用域有什么区别?
3??作用域实在哪个阶段确定的?它的作用是什么?

javascript的作用域是词法作用域,它是在代码编译阶段时根据代码位置决定的,它的作用是规定了变量查找的规则和确定当前代码对变量的访问权限。

4??执行上下文分为哪几类?什么时候会创建执行上下文?如何管理众多的执行上下文?

执行上下文根据可执行代码的种类可以分为全局、函数、eval三类。在函数进行调用时会创建全局上下文。执行上下文栈用于管理执行上下文,当遇到函数调用时就生成一个对应的上下文并入栈,当函数执行完毕时就把对应的上下文出栈。除非整个程序执行完毕,否则全局上下文会一直待在栈底。

思考题

留个思考题,下面两段程序结果是什么?有什么不同吗?

试试用本文的知识使用栈模拟一下其过程!

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:31:32  更:2022-05-09 12:32:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:31:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码