# 作用域与变量提升
- 变量声明的关键词
var
let
const
function
- 变量提升是指 声明式函数及变量的声明都将被提升到作用域
scope
(全局域或者当前函数作用域) 顶部的行为
# 作用域
案例一
var a = 1;
1a
是变量 相当于盒子 用来代表一个值的符号1
是值=
是赋值 将变量和值绑定在一起- 作用域是指变量和值绑定的有效范围
案例二
let a = 'melon'; function f1() { return a; } function f2() { let a = 'ricky'; return f1(); } console.log(f1()); console.log(f2());
1
2
3
4
5
6
7
8
9
10
11
12
13函数
f1
返回变量a
是外层定义的a
函数
f1
和函数f2
没有直接的关系 所以没办法读取f2
定义变量a
# 变量声明和变量赋值
案例一
var a = 1; var b = 2;
1
2- 当我们进行变量声明且赋值时 实际上是分成两步 先声明好所有的变量 然后赋值
var a; var b; a = 1; b = 2;
1
2
3
4案例二
var a = 1; console.log(a); console.log(b); var b = 2;
1
2
3
4- 当有多个变量同时声明赋值时 实际上是声明赋值一个变量 再声明赋值一个变量
var a; var b; a = 1; console.log(a); console.log(b); b = 2;
1
2
3
4
5
6
# 函数声明优先级高于变量声明
案例一
console.log(a); function a() { } console.log(a); var a = 1; console.log(a);
1
2
3
4
5- 不管变量和函数写在什么位置 所有变量声明会被整体提升到作用域顶部 但是函数声明在变量声明的后面
var a; function a() { } console.log(a); console.log(a); a = 1; console.log(a);
1
2
3
4
5
6案例二
function f1() { f2(); function f2() { console.log('我是f2的打印'); } } f1();
1
2
3
4
5
6
7
8
9- 声明式函数会提前到函数最前面 而表达式函数则只会 提前声明不会赋值
function f1() { f2(); let f2 = function () { console.log('我是f2的打印'); } } f1();
1
2
3
4
5
6
7
8
9
# let
和 const
变量声明 (opens new window)
块级作用域
function fn() { let b = 'melon'; if (true) { var a = 'ricky'; let b = 'ricky'; } console.log(a); console.log(b); } fn();
1
2
3
4
5
6
7
8
9
10
11
12
13let b = 'melon'
声明变量b
作用域是整个函数fn
if
语句- 使用
var
声明变量是 函数作用域 所以函数fn
范围内都可以访问变量a
- 使用
let
声明变量是 块级作用域 所以if
范围内访问变量b
是ricky
- 使用
不允许重复声明
var a = 1; let a = 2; // Uncaught SyntaxError: Identifier 'a' has already been declared
1
2暂时性死区
var x = 1; if(true) { console.log(x); //Uncaught ReferenceError: Cannot access 'x' before initialization let x = 2; }
1
2
3
4
5
# 总结
- 代码在正式执行之前先进行一次预编译 首先将变量声明及函数声明提升至当前作用域的顶端 然后代码的正式运行
- 如果当前作用域中存在此变量声明 无论它在什么地方声明 引用此变量时就会在当前作用域中查找
- 作用域其实就是一个 变量绑定的有效范围
- 如果在同一个作用域中存在多个同名函数声明 后面出现的将会覆盖前面的函数声明
- 声明式函数 优先权是最高的 然后是表达式函数和变量声明 按顺序执行
let
和const
声明变量时 因为暂时性死区 所以不能变量提升try...catch
的catch
会延长作用域链with
语句可以手动往作用域链最前面添加一个对象 但是 严格模式下不可用
# 面试题
题目一
var a = 1; function fn() { if (!a) { var a = 10; } console.log(a); } fn();
1
2
3
4
5
6
7
8题目二
var a = 1; function fn() { a = 10; return; function a() { } } fn(); console.log(a);
1
2
3
4
5
6
7
8题目三
var name = 'Ricky'; (function () { if (typeof name === 'undefined') { var name = 'Melon'; console.log('Goodbye ' + name); } else { console.log('Hello ' + name); } })();
1
2
3
4
5
6
7
8
9题目四
(function() { var a = b = 1; })(); console.log(a); console.log(b);
1
2
3
4
5题目五
function f1(a) { var a; return a; } function f2(a) { var a = "Ricky"; return a; } let arr = [f1("Melon"), f2("Melon")]; console.log(arr);
1
2
3
4
5
6
7
8
9
10
11
12