作用域

作用域是一套规则,用于确定在何处以及如何查找变量。
作用域查找会在找到第一个匹配的标识符时停止。

词法作用域

定义在词法阶段的作用域。词法作用域意味着作用域是由书写代码时函数声明的位置决定的。
编译的词法分析阶段基本能够知道全部标识符在哪里以及是怎么声明的,从而能够预测在执行过程中如何对它们进行查找。

JavaScript中有两个机制可以“欺骗”词法作用域:evel(...)和with。
evel 可以对一段包含一个或多个声明的“代码”字符串进行演算,并借此来修改已经存在的词法作用域(在运行时)。
with 本质上是通过将一个对象的引用当作作用域来处理,将对象的属性当作作用域中的标识符来处理,从而创建了一个新的词法作用域(在运行时)。

这两个机制的副作用是引擎无法在编译时对作用域查找进行优化,因为引擎只能谨慎地认为这样的优化是无效的。
使用这其中任何一个机制都将导致代码运行变慢。不要使用它们。

函数作用域

函数作用域是指属于这个函数的全部变量都可以在整个函数的范围内使用及复用(事实上在嵌套的作用域中也可以使用)。

块级作用域

块作用域指的是变量和函数不仅可以属于所处的作用域,也可以属于某个代码块(通常指{...}内部)
with、try/catch、let、const

变量的赋值

变量的赋值操作会经历两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后再运行时引擎会在作用域中查找变量,如果能够找到就会对它赋值,否则引擎就会抛出一个异常。

变量提升

引擎会在解释javascript代码之前首先对其进行编译。编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将他们关联起来。
每个作用域都会进行提升操作

var a = 2;
javascript实际上会将上述代码看成两个声明:
    var a;
      和
    a = 2;
第一个定义声明是在编译阶段进行,第二个赋值声明会被留在原地等待执行阶段。

eg1:
a = 1;
var a;
console.log(a);  //1

eg2:
console.log(a);
var a = 2;
//undefined

`只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。`
function a(){
    console.log(b)
    console.log(c)
    var b = 1
    let c = 2
}
a()
运行结果:undefined 和 ReferenceError


foo() //不是ReferenceError而是TypeError
bar() //ReferenceError
var foo = function bar(){...}

`函数声明会被提升,函数表达式却不会被提升`
`即使是具名函数表达式,名称标识符在赋值之前也无法在所在作用域中使用`
foo() //3
function foo(){
    console.log(1)
}
var foo = function(){
    console..log(2)
}
function foo(){
    console.log(3)
}
`函数声明和变量声明都会被提升,但是函数会首先被提升,然后才是变量`

小知识点

异常类型
ReferenceError 引用错误,不存在的变量被引用时发生的错误
TypeError 类型错误,存在变量,值的类型非预期类型时发生的错误
函数
匿名函数
function(){...} 没有名称标识符

具名函数
function something(){...} 有名称标识符

立即执行函数
函数被包含在一对()括号内部,因此成为了一个表达式,通过在末尾加上另一个()可以立即执行这个函数,
例如:(function(){...})()(function(){...}())

文章摘取来源:《你不知道的JavaScript上卷》


liuxk
91 声望0 粉丝