14

作用域

JavaScript是门动态语言,跟Java不一样,JavaScript可以随意定义全局变量和局部变量,变量会在该作用域下提升,而且JavaScript没有块级作用域。
全局变量就是定义在全局的变量了,局部变量是定义在函数里的变量,每一个函数都是一个作用域,当函数执行时会优先查找当前作用域,然后逐级向上。定义在
if 和 for 语句里的变量,在大括号外面也能访问到,这就是没有块级作用域。

图片描述

一、预处理 + 作用域解析

JavaScript 的作用域只用两种,一个是全局的,一个是函数的,也称为 全局作用域 和 局部作用域 ;局部作用域 可以访问 全局作用域 。但是 全局作用域 不能访问 局部作用域

有这样一段代码

var a = 1;
function fn1(){
    alert(a);
    var a = 2;
}
fn1();
alert(a);

这里先揭晓答案:

第一个 alert(a) 弹出 undefined
第二个 alert(a) 弹出 1

1. 预解析(预编译) 全局作用域 (全局词法环境)

// 全局词法环境
// 第1行,遇到 var 关键字,解析到全局的头部
a = undefined
// 第2行,遇到 function 关键字,解析到全局的头部
fn1 = function fn1(){
    alert(a);
    var a = 2;
}
// 第3行,没有遇到关键字,不解析
// 第4行,没有遇到关键字,不解析

2. 开始执行代码

第1行,遇到表达式 a = 1, a 被赋值成 1 
第6行,遇到函数调用 fn1() ,           ---- 开始 预解析(预编译) 局部-----

3. 预解析(预编译) 局部作用域 (函数词法环境)

// 第3行,没有遇到关键字,不解析
// 第4行,遇到 var 关键字,解析到局部
a = undefined

4. 开始执行 局部 代码

第3行,弹出 undefined
第4行,遇到表达式,把局部 a 改成 2

5. 局部执行完成,继续执行全局

第7行,弹出 1 ,因为全局和局部是两个独立的作用域

二、作用域疑惑之处

1. js没有块作用域

2. js不是动态作用域,js是静态作用域

function f(){
  alert(x);
}
function f1() {
  var x = 6;
  f();
}
function f2() {
  var x = 10;
  f();
}

f1();
// 执行会报错,因此js不是动态作用域哦

二、作用域链

var a = 10;

function f() {
  var x = 100;
  function g () {
    // 
  }
  g();
}
f();
  • 作用域链解析
1. 创建词法环境(window)
2. 加入 a 以及 f函数 ,这时候     【f.scope === window】
3. 进入f函数,创建f函数的词法环境  【f.le => f.scope】
4. 创建f 的词法环境 
5. 添加x和 g函数 到f函数的词法环境 【g.scope === f.le】
6. 进入g函数,创建g函数的词法环境  【g.le => g.scope】
g.le  ->  g->scope  ->  f.le  ->  f.scope  ->  window

三、作用域的本质

var a = 10;

function f() {
  var x = 100;
  function g () {
    // 
    alert(a);
  }
  g();
}
f();

我们在g内部使用了变量a,想要找到a,

  1. 首先在g的词法环境中查找,如果没找到
  2. 到g.scope 也就是 f的词法环境中查找,如果依旧没找到
  3. 到f.scope 也就是 全局词法环境中查找。

Meils
1.6k 声望157 粉丝

前端开发实践者