1、使用var的函数作用域声明
在使用var声明变量时,变量会被自动添加到最接近的上下文。在函数中,最接近的上下文就是函数的局部上下文
function add(num1,num2){
var sum = num1+num2;
return sum;
}
let result = add(10,20); // 30
console.log(sum); // 报错:sum 在这里不是有效变量
这里 add() 定义了一个局部变量 sum,保存加法操作的结果,这个值作为函数的值被返回,但是变量sum在函数外部是访问不到的,
如果省略上面关键字var,那么sum在add()被调用之后,就变成可以访问的了。如下
function add(num1,num2){
sum = num1+num2;
return sum;
}
let result = add(10,20); // 30
console.log(sum); // 30
var的声明会被拿到函数或者作用域顶部,位于作用域中所有代码之前,这种现象叫做变量提升。提升让同一作用域中的代码不必考虑变量是否已经声明就可以直接使用
2、使用let的块级作用域声明
let关键字跟var很相似,但是let是块级作用域,块级作用域是由最近的一对包含花括号{} 界定的,换句话说,if块,while块,function块,甚至连单独的块也是let声明变量的作用域。
if(true){
let a = 10;
}
console.log(a); //报错 a没有定义
while(){
let b=10;
}
console.log(a); //报错 b没有定义
function foo(){
let c = 10;
};
console.log(c); //报错 c没有定义,这个没啥奇怪的,var声明也会报这个错
{
let d = 20;
}
console.log(d); //报错 d没有定义
let 和 var的区别
let和var在同一个作用域内 let生命的变量不能重复声明两次,重复声明的var会被忽略,而重复生命的let会被抛出错误
变量提升和函数提升
什么是提升(Hosting)?
js代码在执行前浏览器引擎会先进行预编译,预编译期间会将变量声明和函数声明提升至对应作用域的最顶端
变量提升
例如:
var 变量提升
console.log(a);
var a = 3;
预编译之后的代码结构如下:
var a; //将变量a的声明提升至最顶端,赋值逻辑不提升
console.log(a); // undefined
a = 3; //进行赋值操作
函数提升
console.log(foo1); // [Function: foo1]
foo1(); // foo1
console.log(foo2); // undefined
foo2(); // TypeError: foo2 is not a function function
//函数声明
foo1 () {
console.log("foo1")
};
// 函数表达式
var foo2 = function () {
console.log("foo2")
};
即函数提升只会提升函数声明,而不会提升函数表达式。 再举一个小例子:
var a = 1;
function foo() {
a = 10;
console.log(a);//10
return;
function a() {}
}
foo();
console.log(a);//1
上面代码经过预编译后可以看做如下形式(只分析foo方法内部情况):
var a= 1;//定义一个全局变量a;
function foo(){ //首先提升函数声明function a(){}到函数作用域顶端,然后function a () {}等同于
// var a = function() {};最终形式如下
var a = function(){}; //定义局部变量a并赋值
a = 10; //修改局部变量a的值,并不会影响全局变量a
conosle.log(a); //输出局部变量a的值:10;
return
}
foo();
console.log(a); // 输出全局变量a的值1
函数提升与变量提升的优先级
console.log(a); // f a() {console.log(10)}
console.log(a()); // undefined
var a = 3;
function a() {
console.log(10) //10
}
console.log(a) //3
a = 6;
console.log(a()); //a is not a function;
上面的代码块经过预编译后可以看做如下形式:
var a = funtion () {
console.log(10)
}
var a;
console.log(a); // f a() {console.log(10)}
console.log(a()); // undefined
a = 3;
console.log(a) //3
a = 6;
console.log(a()); //a() is not a function;
由此可见函数提升要比变量提升的优先级要高一些,且不会被变量声明覆盖,但是会被变量赋值之后覆盖。