likes
comments
collection
share

作用域与变量提升

作者站长头像
站长
· 阅读数 50

作用域

概念:

JavaScript使用词法作用域,词法作用域是根据名称查找变量的一套规则。

作用域嵌套:

当一个块或函数嵌套在另一个块或函数中时,就发生作用域嵌套。在当前作用域中无法找到某个变量时,引擎会在外层嵌套的作用域中继续查找,直到找到该变量,或者抵达最外层的作用域(全局作用域)为止,但外层无法访问里层的变量。(也就是可以从内向外查找,而不能从外向内)。

var a = 'a';
function fun() {
    console.log(a)
};
fun();  // 'a'

修改作用域的两种方式

  1. eval:非严格模式下 eval(..) 中定义的变量在后面可以直接被引用,但严格模式下会抛出错误,注意由于安全和性能问题,我们不应该在开发中去使用它。
  2. with:引用对象到当前作用域中,该对象的属性可以像全局作用域对象属性一样被直接引用,但在with中不会给对象创建新的属性,而是定义到全局对象上。with的性能很差,尽量避免使用
var obj = {a:1, b:2}
with (obj) {
    a = 4;
    b = 5;
    c = 6;
}
console.log(obj.a)  // 4
console.log(obj.c)  // undefined
console.log(c)  // 6

作用域分类

  • 全局作用域
  • 函数作用域:属于这个函数的全部变量都可以在整个函数的范围内使用(包括内部的嵌套)
  • 块级作用域:写在 { } 内部,关键字 letconst
// 块级作用域的几种形式
if (true) {...}
for (let i = 0; i < 5; i++) {...}
with (obj) {...}
try {...} catch (e) {...}

函数声明与表达式

let foo1 = function() {}  // 函数表达式
function foo2() {}  // 函数声明
(function() {})()  //  IIFE-立即执行函数表达式,第一个()将被包裹的函数变成表达式,第二个()执行了这个函数

变量提升

引擎会在解释JavaScript代码之前首先对其进行编译,其中一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来,包括变量和函数在内的所有函数声明都在任何代码被执行前首先被处理

什么是变量提升?

变量和函数声明从它们在代码中出现的位置被移动到了最上面,这个过程就叫做提升,三种作用域都是如此,函数声明与var声明的变量都会被提升,函数表达式不会被提升。 let / const进行的声明也会在块级作用域中进行提升,但是由于暂时性死区的存在使let / const不能在声明之前被使用,这与var的变量提升不太一样,由暂时性死区的存在使得我们无法直观感受到变量提升的效果。

var a = 2;
// 实际会被看成两个声明,var a ; 和 a = 2
// 第一个定义声明是在编译阶段进行的,第二个复制声明会被留在原地等待执行阶段
foo1(); // 执行正确
foo2(); // 执行错误
function foo1() {};
var foo2 = function() {};

在非严格模式下,直接给未经声明的变量赋值,该变量都会成为全局对象的属性

variate = '11';
console.log(window.variate)  // '11'