本文精华:
讲三件事:
1、var、函数声明在预编译时,变量提升【点一】
2、var、函数声明会发生作用域封锁【点二】
3、父级作用域访问子作用域 :块级作用域(可以),函数作用域(不可以)【点三】
子作用域访问父级作用域:块级作用域(可以),函数作用域(可以)
下面是几个例子
例一
var name = 'world';
(function(){
console.log(name)
if(typeof name === 'undefined'){
var name = 'jack'
console.log('goodbye' + name)
}else{
console.log('hello' + name)
}
})()
打印结果:
结果分析:
if 属于块级作用域,里面var声明的name会先在预编译时 提升到立即执行函数的顶部【点一:变量提升】,所以打印‘undefined’ ,因为name还未赋值 默认是‘undefined’。
因此最终进入if中,打印:goodbye jack
例二
console.log(n) // 打印:undefined
// console.log(nn) // 打印:nn is not defined
console.log(fun1) // 打印: undefined
// console.log(fun1()) // 打印:fun1 is not a function
// if判断一直false,也就是说if中的程序一直不会执行,但是var声明的变量和进行的函数声明都在预编译时被添加到window属性中了
if(false){
let nn = '我只属于块级作用域if中,不会被提前编译'
var n = '预编译时,我会被声明,但是不会被赋值'
function fun1(){
console.log('预编译时,我会被声明,但我是不会被赋予函数体的')
}
}
结果分析:【点一:变量提升】
例三
function fun(){
console.log(1)
}
console.log(fun()) // 打印:1
// 块级作用域中var定义的 int 变量被提升到window中
console.log(int); // 打印:100
if(true){
fun() // 打印:块级作用域里的同名封锁
var int = 100;
function fun(){
console.log('块级作用域里的同名封锁')
}
}
(function(){
fun() // 打印:函数里的同名封锁
function fun(){
console.log('函数里的同名封锁')
}
})()
结果分析:【点二:作用域封锁 ==> 同名封锁】
例四
{
// console.log(i) // 打印:cannot access 'i' before init
console.log(v) // 打印:undefined
console.log(f) // 打印:function f(){ console.log('fun') }
let i = 1
var v = 2
function f(){
console.log('fun')
}
}
结果分析:【点一:变量提升】
例五
注意:本例子中的‘子集’概指‘子函数作用域’
if(true){
console.log(int) // 100 (例三的if中定义的int ,在同级作用域中也可以访问)
}
var a = 1;
var b = 1;
// 函数作用域只会向他的父级元素去查找变量,而不会向子集元素去查找,比如立即执行函数。但块级作用域{}不属于子集,块级作用域里的var变量和函数声明可以被父级作用域访问
(function(){
(function(){
var a = 2
})()
if(true){ // 非函数的作用域--块级作用域,域里的var变量或函数声明被添加到父级作用域的属性中,即可以在父级中被访问
var b = 2
let bb = 2
function k_fun(){
console.log('块级作用域中的函数声明')
}
}
console.log(a); // 打印:1
console.log(b ,k_fun); // 打印:2 , k_fun(){ console.log('块级作用域中的函数声明') }
// console.log(bb) // 打印:bb is not defined
})()
结果分析:【点三:父子域间是否可以互相被访问】