js--执行上下文和作用域相关问题
前言
如果你是或者你想成为一名合格的前端开发工作者,你必须知道JavaScript代码在执行过程,知道执行上下文、作用域、变量提升等相关概念,并且熟练应用到自己的代码中。本文参考了你不知道的JavaScript,和JavaScript高级程序设计,以及部分博客。
正文
1.JavaScript代码的执行过程相关概念
js代码的执行分为编译器的编译和js引擎与作用域执行两个阶段,其中编译器编译的阶段(预编译阶段)分为分词/词法分析、解析/语法分析、代码生成三个阶段。
(1)在分词/词法分析阶段,编译器负责将代码进行分割处理,将语句分割成词法单元流/数组;
(2)在解析/词法分析阶段,将上一阶段的词法单元流转换成由元素嵌套组成的符合程序语法结构的抽象语法树;
(3)在代码生成阶段,将抽象语法树转换成可执行代码,并交付给js引擎。
js代码执行的三个重要角色:
(1)js引擎:负责代码执行的整个过程
(2)编译器:负责js代码语法解析和生成可执行代码
(3)作用域:手机并维护所有声明标识符,根据特定规则确定当前代码对声明的标识符的访问权限
2. 执行上下文和执行栈
每当js代码在运行的时候,它都是在执行上下文中运行。说到执行上下文,需要知道什么时执行栈,执行栈,就是其他编程语言中的“调用栈”,是一种拥有LIFO(后进先出)数据结构的栈,被用来存储代码运行时所创建的执行上下文。当js引擎第一次遇到要执行的代码的时候,首先会创建一个全局的执行上下文并压入当前执行栈,每当引擎遇到一个函数调用,它会为该函数创建一个新的执行上下文并压入栈顶,js引擎执行栈顶的函数,当该函数执行完毕,执行上下文从栈中弹出,控制流程到达下一个上下文。对于每一个执行上下文都含有三个重要属性:变量对象,作用域链,this。这些属性也需要彻底理解。
2.1 、上下文调用栈
var scope1 = "global scope";
function checkscope1(){
var scope1 = "local scope";
function f(){
console.log(scope1);
}
return f();
}
checkscope1();
var scope2 = "global scope";
function checkscope2(){
var scope2 = "local scope";
function f(){
console.log(scope2);
}
return f;
}
checkscope2()();
上面两段代码都会输出 local scope
上面代码中scope一定是局部变量,查找块级作用域即可,不管何时何地执行 f(),这种绑定在执行f()时依然有效。出现了一样的结果,但是两段代码的执行上下文栈的变化不一样 :
第一段代码:push(<checkscope1>functionContext)=>push(<f>functionContext)=>pop()=>pop()
第二段代码:push(<checkscope2>functionContext)=>pop()=>push(<f>functionContext)=>pop()
2.2 、三种执行上下文类型
(1)全局上下文
js引擎开始解析js代码的时候首先遇到的就是全局代码,初始化的时候会在调用栈中压入一个全局执行的上下文,当整个应用程序结束的时候才会清空执行上下文栈,栈的最底部永远时全局执行上下文。这是默认的或者说基础的全局作用域,任何函数内部的代码都在全局作用域中,首先创建一个全局的window对象,然后设置this的值等于这个全局对象,一个程序中只有一个全局执行上下文。在顶层js代码中可以使用this引用全局对象,因为全局对象时是域链的头,意味着所有非限定性的变量和函数都作为该对象的函数来查询。
总之,全局执行上下文只有一个,在客户端中一般由浏览器创建,也就是我们熟知的window对象,我们能通过this直接访问到它。
(2)函数上下文
每当一个函数被调用是,都会外该函数创建一个新的上下文,每个函数都拥有自己的上下文,不过是在函数调用的时候创建的,需要注意的是同一个函数被多次调用,都会创建一个新的上下文。
(3)eval和with上下文
执行在 eval和with 函数内部的代码也会有它属于自己的执行上下文,但由于 JavaScript 开发者并不经常使用 eval,所以在这里我不会讨论它。
2.3 、执行上下文创建阶段
执行上下文创建分为创建阶段与执行阶段两个阶段
js引擎在执行上下文创建阶段主要负责三件事:确定this==>创建词法环境组件==>创建变量环境组件(目前还不太理解)
(1)确定this,这个不做详解
(2)创建词法环境组件
词法环境是一种规范类型,基于 ECMAScript 代码的词法嵌套结构来定义标识符和具体变量和函数的关联。一个词法环境由环境记录器和一个可能的引用外部词法环境的空值组成。其中环境记录用于存储当前环境中的变量和函数声明的实际位置;外部环境引入记录很好理解,它用于保存自身环境可以访问的其它外部环境,那么说到这个,是不是有点作用域链的意思?
词法环境有两种类型:
- 全局环境(在全局执行上下文中)是没有外部环境引用的词法环境。全局环境的外部环境引用是 null。它拥有内建的 Object/Array/等、在环境记录器内的原型函数(关联全局对象,比如 window 对象)还有任何用户定义的全局变量,并且
this的值指向全局对象。 - 在函数环境中,函数内部用户定义的变量存储在环境记录器中。并且引用的外部环境可能是全局环境,或者任何包含此内部函数的外部函数。
- 全局环境(在全局执行上下文中)是没有外部环境引用的词法环境。全局环境的外部环境引用是 null。它拥有内建的 Object/Array/等、在环境记录器内的原型函数(关联全局对象,比如 window 对象)还有任何用户定义的全局变量,并且
(3)创建变量环境组件
变量环境可以说也是词法环境,它具备词法环境所有属性,一样有环境记录与外部环境引入。在ES6中唯一的区别在于词法环境用于存储函数声明与let const声明的变量,而变量环境仅仅存储var声明的变量。
3. JavaScript作用域和作用域链
3.1、作用域
词法作用域是在写代码或者定义的时候确定的,而动态作用域是在运行时确定的,(this也是)词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用,JavaScript采用词法作用域,其作用域由你在写代码是将变量和块作用域写在哪里决定,因此当词法分析器处理代码时会保持作用域不变。可以理解为作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
理解作用域之前先来看一道题
function foo() {
console.log(value);
}
var value = 1;
function bar() {
var value = 2;
console.log(value);
foo();
}
bar();
上面的代码会输出什么呢,首先在全局上下文中声明foo()函数、value变量(其值为undefined)、bar()函数,代码执行阶段,bar函数上下文入栈并执行,打印出value为2,然后执行foo(),foo()入栈,打印value时找不到该变量,js引擎会查找上层作用域,即全局作用域,于是打印出1。后面函数执行完毕上下文出栈。再来看下面这个函数,作用域是分层的,内层作用域可以访问外层作用域的变量,反之则不行。

ES6以来,js中的作用域分为全局作用域,函数作用域,块级作用域和欺骗作用域。
3.1.1、全局作用域
在代码中任何地方都能访问到的对象拥有全局作用域,最外层函数和在最外层函数外面定义的变量拥有全局作用域,所有末定义直接赋值的变量自动声明为拥有全局作用域。
3.1.2、函数作用域
3.2、作用域链
作用域链本质上就是根据名称查找变量(标识符名称)的一套规则。规则非常简单,在自己的变量对象里找不到变量,就上父级的变量对象查找,当抵达最外层的全局上下文中,无论找到还是没找到,查找过程都会停止。查找会在找到第一个匹配的变量时停止,被称为遮蔽效应

js--执行上下文和作用域相关问题的更多相关文章
- Js 执行上下文和作用域
1.执行上下文和执行栈 执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行. 执行上下文的生命周期包括三个阶 ...
- js - 执行上下文和作用域以及闭包
首先,咱们通常被"执行上下文","执行上下文环境","上下文环境","执行上下文栈"这些名词搞混.那我们一一来揭秘这些名 ...
- js执行环境、作用域
js执行环境.作用域 执行环境:是javascript中的一个重要的概念,<javascript高级程序设计第三版>的定义是:执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行 ...
- 【repost】 原生JS执行环境与作用域深入理解
首先,我们要知道执行环境和作用域是两个完全不同的概念. 函数的每次调用都有与之紧密相关的作用域和执行环境.从根本上来说,作用域是基于函数的,而执行环境是基于对象的(例如:全局执行环境即window对象 ...
- 浅谈JS执行环境及作用域
今天刚刚开通博客,也是第一次写博文,略感紧张.作为一个表达能力弱弱的人来说,自己花三分钟理解一个知识点,当别人问起时,也许需要30分钟才只是让别人知道自己在说什么,一点也不夸张,希望在博客上可以练习 ...
- JS执行环境,作用域链及非块状作用域
JS中的执行环境,顾名思义就是变量或函数所执行时的环境.在我的理解中,执行环境和作用域相差不大. 每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中.而在函数执行之后 ...
- JS 执行环境与作用域链
1.执行环境 JavaScript 代码都是在执行环境中被执行的.执行环境是一个概念,一种机制,用来完成JavaScript运行时在作用域.生命周期等方面的处理,它定义了变量或函数是否有权访问其他数据 ...
- js执行上下文和执行栈
执行上下文就是JavaScript 在被解析和运行时环境的抽象概念,JavaScript 运行任何代码都是在执行上下文环境中运行的,执行上下文包括三个周期:创建——运行——销毁,重点说一下创建环节. ...
- js执行上下文栈和变量对象
JavaScript执行上下文栈和变量对象 JS是单线程的语言,执行顺序肯定是顺序执行,但是JS 引擎并不是一行一行地分析和执行程序,而是一段一段地分析执行,会先进行编译阶段然后才是执行阶段. 例子一 ...
随机推荐
- Docker Hub公共镜像仓库的使用
创建账号并登陆这里是登陆入口 登陆账号 登陆进入之后里面目前仓库,现在去创建一个 下面我选的是公共仓库,别人也可以访问到 在服务器上登陆进来,进行上传镜像到仓库 [root@docker ~]# do ...
- [APUE] 文件 I/O
文件操作相关 API:open, read, write, lseek, close. 多进程共享文件的相关 API:dup, dup2, fcntl, sync, fsync, ioctl. 文件操 ...
- 小试牛刀ElasticSearch大数据聚合统计
ElasticSearch相信有不少朋友都了解,即使没有了解过它那相信对ELK也有所认识E即是ElasticSearch.ElasticSearch最开始更多用于检索,作为一搜索的集群产品简单易用绝对 ...
- 使用smartform打印表单
昨天写了个smartform打印表单,在开发完成,在测试机测试OK,传到生产机,出现严重问题!无法打印,干脆就是无法调用打印图形界面,进入SMARTFORM事物,查看这个表单,发现,居然公司的LOGO ...
- SAP中数据库表长度的界定
SAP中,如何查看表和关键字的长度?通过SE11菜单栏Extras->table width 可以看到.然而SAP在系统也会将表分类,特别是在可扩展的表维护视图中,分为如下几类 ult ...
- 微服务网关1-Spring Cloud Gateway简介
一.网关基本概念 1.API网关介绍 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各 ...
- NIO非阻塞网络编程原理
NIO非阻塞网络编程原理 1.NIO基本介绍 Java NIO 全称 java non-blocking IO,是指 JDK 提供的新 API.从 JDK1.4 开始,Java 提供了一系列改进的 输 ...
- Vim中的swp文件,在vim非正常退出时,再次编辑会出问题
vim中的swp即swap文件,在编辑文件时产生,它是隐藏文件,如果原文件名是data,那么swp文件名就是.data.swp.如果文件正常退出,则此文件自动删除.以下两种情况不会删除swp文件: V ...
- 代理模式详解:静态代理+JDK/CGLIB 动态代理实战
1. 代理模式 代理模式是一种比较好的理解的设计模式.简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标 ...
- dij的优先队列边表优化
dij的复杂度为v*v,通过优先队列优化后为e*logv. (第一次写,没有过多的测试,不保证对.只当是测试blog了!) #include<cstdio> #include<ios ...