var name="World";
(function(){
if(typeof name==='undefined'){
var name='Jack';console.log('Goodbye'+name);
}else{
console.log('hello '+name);
}
})()
函数作用域内var变量声明提升: 变量的声明会提升到当前作用域的顶部
等价于:
var name = "World";
(function () {
var name //声明提升
if (typeof name === 'undefined') {
name = 'Jack';
console.log('Goodbye' + name);
} else {
console.log('hello ' + name);
}
})()
var name = "World";
(function () {
if (typeof name === 'undefined') {
name = 'Jack';//声明全局变量
console.log('Goodbye' + name);
} else {
console.log('hello ' + name);
}
})()
输出:hello World
注意:
ES5中只有全局作用域和函数作用域。函数作用域的同名变量覆盖了全局作用域该变量的值。
为什么需要块级作用域?
ES5中只有全局作用域和函数作用域,带来了很多不合理的场景。
场景一:内部的变量可能会覆盖外层变量
var temp = new Date();
function f() {
console.log(temp);
if(false){//即使为false
var temp = "hello world";
}
}
f();
//输出 undefined
原因是变量提升导致内部的变量覆盖了外层的temp变量,ES5中,不管会不会进入if代码块,变量都会提升到当前作用域顶部。
场景二:用来计数的循环变量泄漏为全局变量
var s= 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i);//5
上述代码,变量i只是用来控制循环,但在循环结束后,它并没有消失,而是泄漏成了全局变量。
(function () {
var name; //声明提升
})()
console.log(name);//ReferenceError: name is not defined
立即执行函数的作用域是可以访问全局的, 全局的无法访问立即执行函数
立即执行函数内部可以看作是一个块作用域, 与外层不是同一个作用域了, 查找变量是也是会一层一层作用域往上找, 先在当前的作用域中找, 找不到才往上一个作用域找。 然后 var 声明是会提升到当前作用域最顶层, 也就是立即执行函数内部的最顶层, 所以执行if时 是会找到var name 这句的。 (如果改成const let 这种是不会提升变量的, 那if就找不到 会返回hello world )
ES6中的块级作用域,使得广泛使用的立即执行匿名函数不再必要了。
另外ES6也规定,函数本身的作用域在其所在的块级作用域之内。
function f() {
console.log('I am outside!');
}
(function () {
if(false){
function f() {
console.log('I am inside!');
}
}
f();
}())
在ES5中运行,得到I am inside!,在ES6中运行,得到I am outside!。这是因为ES5中存在函数提升,不管会不会进入if代码块,函数声明都会提升到当前作用域的顶部而得到执行;而ES6支持块级作用域,不管会不会进入if代码块,其内部声明的函数皆不会影响到作用域的外部。
例子
const a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[1]()
//输出 1
知识点:变量i是let声明的,当前i只在本轮循环有效。所以每一次循环的i其实都是一个新的变量。
注意:ES6不存在变量提升