1. js是编译语言,但是它不是提前编译,编译结果不能在分布式系统中移植。大部分情况下,js的编译发生在代码执行前的几微秒(甚至更短)

2. 一般的编译步骤  

  • 分词/词法分析:把字符串分解成词法单元
  • 解析/语法分析:将词法单元转换成一个由元素组成的语法结构树,抽象语法树AST
  • 代码生成:将AST转换成一组机器指令

3. 三个工具

  • 引擎:控制整个程序的编译及执行过程
  • 编译器:负责语法分析及代码生成等
  • 作用域:收集并维护所有声明的标识符的访问权限

4. var a = 2 的编译过程

var a=2; --分解成-->

词法单元

var a = 2; =>

var、a、=、2

--解析成-->

树结构

AST

--代码生成-->

1. var a:询问作用域是否有a。

如果有,则忽略。如果没有,则在当前作用域添加一个声明a

2. a = 2:当前作用域是否有a,

如果有,则赋值。如果没有,则向上一层作用域查找

5. 代码生成中查找判断作用域是否存在某个变量的两种查找类型

  LHS RHS
直观区别 变量在=左侧 变量不在=左侧
操作 对变量赋值 取变量的值
找不到?

1. 严格模式

抛出ReferenceError异常

2. 非严格模式

自动隐式创建一个全局变量

抛出ReferenceError异常

6. 作用域

  • 词法作用域

定义在词法阶段的作用域。也就是在写代码时将变量和块作用域写在哪决定的。函数的作用域完全由声明时的位置决定

    • 全局作用域
    • 函数作用域:每声明一个函数就会创建一个作用域。在该作用域内声明的变量或函数(标识符)都附属于它,可在整个函数范围内被使用。
    • 块作用域
var
//变量绑定在所在的函数内
(function c(){
//a是局部变量,b是全局变量
  var a = b = 3;
})()
(function c(){
//a和b都是局部变量
  var a = 1, b = 3;
})()
try/catch
try{
  //异常操作
//catch创建一个块作用域,这里的变量只能在catch中使用
}catch(err){
  //只有这里可以访问err
}
let

ES6新引入的。将变量绑定在所在任意作用域{}中

在循环中for(let i = 1; i < 5; i++),i在每次迭代中会声明,且每次迭代会用上一个迭代结束时的值来初始化

const ES6新引入的,将变量绑定在所在任意作用域{}中,且值是固定不可修改的
  • 运行时修改作用域  eval、with

7. 作用域嵌套

在一个作用域A内创建一个新的作用域B,则B被嵌套在A中

B可以访问A中的标识符。A不可以访问B中的标识符

最外层的作用域是全局作用域

作用域层层嵌套形成作用域链,在访问查找一个标识符时从最内层开始向外查找,一旦找到就停止,因此会出现外层的标识符被内层同名的所屏蔽

8. 闭包

在各个文章中对闭包进行了解释,但是好像有很多说法。我理解得了的一个说法是:

当函数可以记住并访问所在的词法作用域时,就产生了闭包

函数A创建一个作用域A,在A中声明一个函数B(创建了作用域B),把函数B作为结果返回,作用域B会记得自己的作用域链,利用B可以向上层作用域访问

9. 循环和闭包(一个好像特别常见的例子)

for( var i = 1; i <= 5; i++){
setTimeout(function timer(){
console.log(i);
}, i*1000);}

说明:

var i = 1:定义了一个全局变量

setTimeout():在i秒后执行timer函数。timer是回调函数,在for循环执行完成才开始调用。timer会记住循环的作用域

结果:for执行完成后开始调用timer,以每秒一次的频率输出5次6

期待:每秒一次输出1,2,3,4,5

结果解释:

setTimeout时并没有让timer保存i的副本

timer函数执行时,会去引用i的值,这时只有一个i=6

修改1——立即执行

for(var i = 1; i <=5; i++){
(function(){
setTimeout(function timer(){
console.log(i);
}, i*1000);
})();}

结果:以每秒一次的频率输出5次6

即使是立即执行,最后访问的变量也是全局的i

修改2——立即执行+参数

for(var i = 1; i <=5; i++){
(function(j){
setTimeout(function timer(){
console.log(i);
}, i*1000);
})(i);}

结果:每秒一次输出1,2,3,4,5

修改3——块作用域循环变量

for(let i = 1; i <=5; i++){
setTimeout(function timer(){
console.log(i);
}, i*1000);
}

结果:每秒一次输出1,2,3,4,5

修改4——在循环中添加一个变量var j

for(var i = 1; i <=5; i++){
var j = i;
setTimeout(function timer(){
console.log(j);
}, j*1000);
}

结果:以每秒一次的频率输出5次5(j和i一样为全局变量,j=5)

修改5——块作用域变量

for(var i = 1; i <=5; i++){
let j = i;
setTimeout(function timer(){
console.log(j);
}, j*1000);
}

结果:每秒一次输出1,2,3,4,5

参考

1. 《你不知道的javascript》上卷

2. 还看了很多网上的说明,就不一一列举了,因为没记住具体哪些了

js——作用域和闭包的更多相关文章

  1. JS作用域与闭包

    JS作用域与闭包 在JavaScript中,作用域是可访问变量,对象,函数的集合. 变量分为全局变量和局部变量.全局变量在函数外定义,HTML中全局变量是window对象,所有数据对象都属于windo ...

  2. js作用域及闭包

    作用域 执行环境是js最为重要的一个概念.执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为. 1.全局执行环境就是最外围的一个执行环境,每一个函数都有自己的作用域 2.简单的说局部作用 ...

  3. JS作用域与闭包--实例

    <script> "use strict" //函数作用域 function func(){ var arr = [1,3,5,7,9]; var sum = 0; f ...

  4. 浅谈JS作用域和闭包

    函数表达式和函数声明 变量/函数声明都会提前 console.log(a) let a =1 那么打印出来的a为 undefined,因为会将a提到前面并赋予默认值undefined 函数声明:函数声 ...

  5. js闭包的作用域以及闭包案列的介绍:

    转载▼ 标签: it   js闭包的作用域以及闭包案列的介绍:   首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...

  6. JS教程:词法作用域和闭包 (网络资源)

    varclassA = function(){ ; } classA.prototype.func1 = function(){ var that = this, ; function a(){ re ...

  7. 原来JS是这样的 - 提升, 作用域 与 闭包

    引子 长久以来一直都没有专门学过 JS ,因为之前有自己啃过 C++ ,又打过一段时间的算法竞赛(写得一手好意大利面条),于是自己折腾自己的网站的时候,一直都把 JS 当 C 写.但写的时候总会遇到一 ...

  8. js面试题知识点全解(一作用域和闭包)

    问题: 1.说一下对变量提升的理解 2.说明this几种不同的使用场景 3.如何理解作用域 4.实际开发中闭包的应用 知识点: js没有块级作用域只有函数和全局作用域,如下代码: if(true){ ...

  9. 解析js中作用域、闭包——从一道经典的面试题开始

    如何理解js中的作用域,闭包,私有变量,this对象概念呢? 就从一道经典的面试题开始吧! 题目:创建10个<a>标签,点击时候弹出相应的序号 先思考一下,再打开看看 //先思考一下你会怎 ...

随机推荐

  1. 20155324 2016-2017-2 《Java程序设计》第十周学习总结

    20155324 2016-2017-2 <Java程序设计>第十周学习总结 教材学习内容总结 Java的网络编程 网络编程 网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据. ...

  2. python中执行py文件出错(提示File “<stdin>”,line 1,SyntaxError:invalid syntax)

    解决办法: 上图中已通过输入python进入了python运行环境,出现>>>时候的不能再用python z.py 来运行hello.py文件: 应该通过exit()退出当前pyth ...

  3. Docker --rm 自动清理容器内部临时文件

    在Docker容器退出时,默认容器内部的文件系统仍然被保留,以方便调试并保留用户数据. 清除断掉链接的容器缓存

  4. GIT原理【摘】

  5. Python11 RabbitMQ Redis

    本节内容 1.RabbitMQ 2.Redis RabbitMQ队列 安装 http://www.rabbitmq.com/install-standalone-mac.html 安装python r ...

  6. react-踩坑记录——iconfont

    选取图标,添加至购物车后,下载代码. 后将下载了的文件夹改名,放入css文件夹中.在组件中使用到的时候按路径引入“iconfont.css”文件即可. 使用

  7. 1 Java中的时间类型

    总结:sql中的时间转 util的时间直接赋值即可:反过来,必须先吧util下的时间转换成毫秒,再通过sql的构造器生成sql的时间格式. 1 Java中的时间类型 java.sql包下给出三个与数据 ...

  8. 51NOD 数字1的数量

    题目描述: 给定一个十进制正整数N,写下从1开始,到N的所有正数,计算出其中出现所有1的个数. 例如:n = 12,包含了5个1.1,10,12共包含3个1,11包含2个1,总共5个1. Input ...

  9. Java9 新特性

    Java9中的9个新特性 1. Java 平台级模块系统 2. Linking 3. JShell: 交互式 Java REPL 4. 改进的 Javadoc 5. 集合工厂方法 6. 改进的 Str ...

  10. 【ARTS】01_18_左耳听风-20190311~20190317

    ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...