引子
这篇文章源于几道面试题。
//demo 01
{
function test() {}
test = 123
}
console.log("test", test)
{
test00 = 123
function test00() { }
}
console.log("test00", test00)
// demo 02
{
function test01() {
}
var test01 = 123
}
console.log("test01", test01)
// demo 03
{
var test02 = function () {}
var test02 = 123
}
console.log("test02", test02)
// demo 04
{
function test03() {}
test03 = 123
function test03() {}
}
console.log("test03", test03)
// demo 05
{
function test04() {}
test04 = 123
function test04() {}
test04 = 234
}
console.log("test04", test04)
以上是第一道面试题,打印的结果把我打印懵逼了都,虽然现实中没人这样写奇葩的代码,但是不好意思,最传统的极度灵活的js需要这种面试题😡
就此引进了函数声明和变量声明、独特的声明提升Hositing、块级作用域、默认变量(即没有用let const var
等关键字就初始化的变量)。
函数声明、变量声明、js作用域入门
在ES6之前
,变量声明有且只有两种方式,var
和 function开头的函数声明
,而且没有块级作用域的概念,只有函数作用域和全局作用域。
作为一个严谨的程序员,我们应该秉持变量先声明再使用的顺序,但是早期js
过于动态的特点导致了很多奇奇怪怪的面试题,我们既要去其糟粕,取其精华,也要追本溯源,了解那些黑暗的故事。
不声明会怎样
先看最基础的变量声明:
console.log(a) // undefined
var a = 1
console.log(a) // a
以上是最基本的测试,结果对于任何一个前端来说,闭着眼睛都能答对。
说明js
变量可以声明提升
//等价于
var a
console.log(a)
a = 1
console.log(a)
而且此时的a
变量也被挂载到了顶级对象window
中,也就是说此时的全局变量和顶级对象耦合很紧密。
我们看看函数声明和变量声明一起使用会发生什么:
var a = 1
function test() {
console.log(a) //undefined
var a = 10
console.log(a) // 10
}
test()
console.log(a) // 1
可以发现,函数声明有单独的作用域,里面的同名变量a
只能在局部作用域中使用,函数声明之外的位置不能访问,函数体内的变量声明会被提升到当前局部作用域的顶部,但是只有声明提升,赋值语句保持原位置
即:
function test() {
var a
console.log(a)
a = 10
console.log(a)
}
那么问题来了:
var a = 1
function test() {
console.log(a) // 1
a = 10
console.log(a) // 10
}
test()
以上函数体内没有变量声明,只有a = 10
,打印时按照怎么个顺序去获得a的值呢,答案在作用域链和默认变量
作用域链
对于