函数声明和函数表达式最重要的区别是它们的名称标识符将会绑定在何处
函数声明
var a=2;
// 具名函数声明
function foo(){
var a=3;
console.log(a) // 3
}
// 具名函数调用
foo();
console.log(a) // 2
上面的片段foo被绑定在作用域中,直接通过foo()来调用
var a=2;
(function foo(){
var a=3;
console.log(a)
})();// ()代表调用
console.log(a)
第一个()将函数变成表达式,第二个()执行了这个函数
上面的片段foo被绑定在函数表达式自身的函数中,而不是所在作用域中。换句话说(function(){…})作为函数表达式意味着foo只能在…所代表的位置中访问,外部作用域中则不行
匿名和具名
setTimeout(function(){
console.log('i love you')
},1000)
这是匿名函数表达式,因为function()没有名称标识符,函数表达式可以匿名,然而函数声明不可以匿名
给函数表达式指定一个函数名
setTimeout(function foo(){
console.log('i love you')
},1000)
立即执行函数表达式
var a=2;
obj={
a:4
};
(function foo(ee){
var a=3;
console.log(a); // 3
console.log(ee.a); // 4
})(obj);
console.log(a); // 2
块作用域
for(var i=0;i<5;i++){
console.log(i) // 0 1 2 3 4
}
console.log("nihao")
console.log(i) // 5
我们在for中声明了变量i,是因为只想在for循环的上下文中使用i,
使用var声明变量时,写在那里都一样,因为它最终都会属于外部作用域
let关键字可以将变量绑定在所在的任意作用域中,通常是{…}内部。
var foo=true;
if(foo){
{ //显示的块,bar只作用于当前块中
let bar=foo*2;
console.log(bar);
}
console.log(bar);
}
使用let进行的声明不会再块作用域中进行提升
console.log(bar) // ReferenceError
let bar=2;
let和var的大区别
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
是因为在退出循环时,迭代变量保存的是导致循环退出的值: 5。在之后执行超时逻辑时,所有的 i 都是同一个变量,因而输出的都是同一个最终值。
for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
在使用 let 声明迭代变量时, JavaScript 引擎在后台会为每个迭代循环声明一个新的迭代变量。每个 setTimeout 引用的都是不同的变量实例,所以 console.log 输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值