变量提升与函数提升
var let const 区别
var 和 let 的作用域规则一样,其声明的变量只在其声明的块或子块中可用
例子: 作用域、重复声明
function varTest() {
var a = 1;
{
var a = 2; // 函数块中,同一个变量
console.log(a); // 2
}
console.log(a); // 2
}
function letTest() {
let a = 1;
{
let a = 2; // 代码块中,新的变量
console.log(a); // 2
}
console.log(a); // 1
}
varTest();
letTest();
例子: 全局绑定
var foo = 'global'
let bar = 'global'
console.log(this.foo) // global
console.log(this.bar) // undefined
暂时性死区 TDZ
当程序的控制流程在新的作用域进行实例化时,在此作用域中用let/const声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,所以是不能被访问的,如果访问就会抛出错误。因此,在这运行流程进入作用域创建变量,到变量可以被访问之间的这一段时间,就称之为暂时死区。
例题
例子1
function b(){};
var b = 11;
typeof b;
预编译后↓
function b; // => 声明一个function b
var b; // =》 声明一个变量 b
b = (){}; // =》 function b 初始化
b = 11; // =》 变量 b 初始化 =》变量初始化没有被提升,还在原位
typeof b; // number
例子2
var foo = 'hello';
(function(foo){
console.log(foo);
var foo = foo || 'world';
console.log(foo);
})(foo);
console.log(foo);
//
//
//
// 依次输出 hello hello hello
预编译后↓
var foo = 'hello';
(function (foo) {
var foo; // undefined;
foo= 'hello'; //传入的foo的值
console.log(foo); // hello
foo = foo || 'world';// 因为foo有值所以没有赋值world
console.log(foo); //hello
})(foo);
console.log(foo);// hello,打印的是var foo = 'hello' 的值(变量作用域)
例子3
console.log(a, b)
var a =12, b ='666'
function foo(){
console.log(a, b)
var a = b =13
console.log(a, b)
}98
foo()
console.log(a, b)
// 输出:
//
/*
undefined undefined
undefined "666"
13 13
12 13
*/
例子4
fn();
console.log(v1);
console.log(v2);
console.log(v3);
function fn() {
var v1 = v2 = v3 = 2019;
console.log(v1);
console.log(v2);
console.log(v3);
}
/*
输出
2019
2019
2019
Uncaught ReferenceError: v1 is not defined
/
例子5
console.log('1',fn())
function fn(){
console.log(1)
}
console.log('2',fn())
function fn(){
console.log(2)
}
console.log('3',fn())
var fn = '林一一'
console.log('4',fn())
function fn(){
console.log(3)
}
/* 输出
* 3
* 1 undefined
* 3
* 2 undefined
* 3
* 3 undefined
* Uncaught TypeError: fn is not a function
/
例子6
let a = 0, b = 0;
function fn(a) {
fn = function fn2(b) {
console.log(a, b)
console.log(++a+b)
}
console.log('a', a++)
}
fn(1); // a, 1
fn(2); // 2, 2 5
例子7
var a = 10;
(function () {
console.log(a)
a = 5
console.log(window.a)
var a = 20;
console.log(a)
})()
var b = {
a,
c: b
}
console.log(b.c);
//
//
// undefined 10 20 undefined
例子8
var a = 1;
function foo(a, b) {
console.log(a);
a = 2;
arguments[0] = 3;
var a;
console.log(a, this.a, b);
}
foo(a);
//
//
// 1
// 3, 1, undefined
思考题
带var和不带var的区别
全局作用域中不带var声明变量相当于给window对象设置一个属性。
私有作用域(函数作用域),带 var 的是私有变量。不带 var 会沿作用域链查找。
函数的形参也会进行一次变量提升
var foo = '666';
(function(f){
console.log(foo);
var foo = f || 'hello';
console.log(foo)
})(foo);
console.log(foo)
//
//
// undefined, 666,666
if语句中的变量提升
- 在当前作用域中不管条件成立都会进行变量提升
- if 中
()内的表达式不会变量提升 - JS 执行到条件语句,判断条件是成立的才会对条件内的函数
赋值,不成立不被赋值只被定义成undefined1
if()内是单独的作用域?
var y = 1
if(function f(){}){
console.log(typeof f) // undefined
y = y + typeof f
}
console.log(y) // 1undefined
2
console.log(print()) // == window.print()
if(true){
function print() {
console.log('666')
}
}
console.log(print())
/* 输出
undefined
666
undefined
*/
匿名自执行函数在自己的作用域内存在正常的变量提升
var a = 10;
(function(){
console.log(a)
a = 20
console.log(a)
})()
console.log(a)
// 10, 20, 20
非匿名自执行函数的函数名在自己的作用域内变量提升,且修改函数名的值无效
var a = 10;
(function a(){
console.log(a)
a = 20
console.log(a)
})()
// ƒ a(){a = 20 console.log(a)} ƒ a(){a = 20 console.log(a)}