《你不知道的JS》(上)第一部分的学习笔记

作用域和闭包

第一章

编译原理:(三步走)

  • 分词/词法分析:将代码块分解为一个个的词法单元
  • 解析/语法分析:将词法单元流(数组)转换为抽象语法树(AST)
  • 代码生成:将AST转换为可执行代码的过程

变量赋值操作过程:1)编译器在当前编译器会在当前作用域中声明一个变量(如果之前没有声明过)  2)在运行时引擎会在作用域中查找该变量,如果能够找到就会对它赋值
赋值操作时候的引擎的查找过程

  • LHS查询 —— 赋值操作的目标是谁;试图找到变量的容器本身
  • RHS查询 —— 谁是赋值操作的源头;得到某某的值

常见的两个错误:

  • ReferenceError异常 —— 在所有嵌套的作用域中遍寻不到所需的变量
  • TypeError异常 —— 试图对一个非函数类型的值进行函数调用,或着引用null或undefined类型的值中的属性

特别的,当变量未声明时对变量进行查询:

  • 如果RHS查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出ReferenceError异常
  • 在非“严格模式”下,当引擎执行LHS查询时,如果在顶层(全局作用域)中也无法找到目标变量,全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎


第二章

欺骗词法的两个函数

  • eval() —— 接受了含有一个或多个声明的代码,就会修改其所处的词法作用域
  • with(){} —— 根据你传递给它的对象凭空创建了一个全新的词法作用域  尽管with块可以将一个对象处理为词法作用域,但是这个块内部正常的var声明并不会被限制在这个块的作用域中,而是被添加到with所处的函数作用域中。


第三章

let

  • let的作用 —— 将变量绑定到所在的任意作用域{...}中,如for(...){...} 、 if(...){...}
  • 特别的,在使用let的时候声明变量不会被提升,如果在声明之前使用let,则会报错。相反的,使用var声明变量会被提升,且在for和if的{}中使用var声明的变量会被暴露在他们的父作用域中。
  • for循环头部的let不仅将i绑定到了for循环的块中,事实上它将其重新绑定到了循环的每一个迭代中,确保使用上一个循环迭代结束时的值重新进行赋值

任何声明在某个作用域内的变量,都将附属于这个作用域



第四章

声明提升

  • 不管声明写在代码中的那个位置,声明都会在编译阶段进行,而赋值会在执行阶段进行,所以声明会被提升,且只有声明会被提升,其余代码都按照原有位置的次序执行
  • 同样的函数声明会被提升,但注意提示的只有声明会被提升,函数表达式是不会被提升的 如var foo = function bar() {}; 不会被提升,若在此语句前调用了foo()则会报TypeError错误,调用bar()则会报ReferenceError错误
  • 当有多个声明的时候,函数声明提前之后再是变量声明。如果此时声明了多个函数名相同的函数,则最终调用此函数名时,调用的时候最后一个此函数名的函数,即后面的函数覆盖了前面的函数


第五章

闭包

  • 闭包是指在一个函数a内部定义一个函数b并将其返回赋值给一个变量c,那么通过变量c调用函数b时,在b函数的内部就可以访问到a函数内部定义的一些属性或方法。换句话说就是,b函数的词法作用域就是a函数的内部作用域。
  • 模块的机制就是:在一个js文件中定义函数并将其导出,之后在其余js文件中导入就可通过导入名.函数名调用在导入JS文件中的函数。整个过程类似于,定义一个函数a,在a中定义几个函数,并返回一个包含这些函数的对象。调用函数将返回的对象赋值给一个变量b,则我们通过b.函数名就可以调用a函数中定义的函数,且还可以访问a函数中定义的属性。


猜你喜欢

转载自blog.csdn.net/m0_37747665/article/details/81066490