var
不知道你是否和我一样,每次在js中只会用var?用webstorm的小伙伴都知道,每次用WebStorm,都会提示把var改成const或者let。
这其实是ECMAScript6的语法规范,推荐我们用const和let去替代var。ok那么为什么要这样呢?
先来讲讲var:
var声明变量主要有三个特点:
1.变量的声明,会在代码被执行之前被处理。
2.在函数内声明的变量,其可用范围在当前函数作用域内。
3.在函数外声明的变量,其作用范围是全局。
来看下面的代码
//js
(function f() {
var a =10;
console.log(a); // 输出 10
{
var a=20;
console.log(a); // 输出 20
}
console.log(a); // 输出 20
})();
console.log(a);
运行结果:
结论:可以看出,在函数内用var声明的变量作用仅在这个函数内,而对函数外部是不作用的。
那对这个代码稍作修改:
//js
var a = 10;
(function f() {
console.log(a);
{
var a=20;
console.log(a);
}
console.log(a);
})();
console.log(a);
运行结果:
第一个变量变成undefined是怎么回事?
会出现undefined,无非就是两种情况,首先,声明了变量没有赋值,在这里显然不是,那么就是变量提升了。
什么是叫变量提升?简单来说就是:用var声明的变量可以在声明之前使用,值为undefined。 如:
//js
console.log(a); // 输出undefined
var a = 2;
那么,为什么会发生这种情况呢?在js中有个特性:层级关系作用域内会优先查找已经在内部声明的变量。
所以,即使在函数外面对一个变量赋值一旦在函数里面用var声明了变量,函数里面再赋值,那么就会忽略掉函数外部的赋值,从而导致了变量提升。
有一说一,这么解释确实不太严谨。这其实和JS作用域与作用域链有关。可以参考JS作用域与作用域链
let
接着说说let
let的主要特点:
1.不允许在相同作用域内,重复声明同一个变量(代码规范!)
2.不存在变量提升
3.块级作用域
来看下面的代码
//js
{
let a = 10;
var b = 1;
}
console.log(b);
console.log(a);
let与var最大的不同在于其作用域不同,let的声明只在它所在的代码块有效,这就是块级作用域,而var声明的变量类似于其它语言中的全局变量。
在其它很多语言里,比如C语言,Java,在写for循环的时候都会保证计数器i只在循环体内有效,在js里,如果用var去声明 i, 如:
//js
for (var i = 0; i < 10; i++) {
// 执行相关代码
}
console.log(i);//输出10
循环结束,这个i仍然是有效的,因为是var声明的。而这样写可能会出问题哦
比如:
//js
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 输出10
输出的结果是10,并不是我们想要的6。就是因为变量i是var声明的,在全局范围内都有效,所以可以理解为全局只有一个变量i,而数组里的每一个函数指向的都是同一个i,所以最后的输出结果是10.
for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
//js
var a = [];
//将var改成let就可以了
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 输出6
const
const声明的变量只能被赋值一次,然后就不能在被赋值。const语句的作用范围和let语句一样。根据命名规范我们应该用大写字母声明常量。
注意:不能给const重新赋值
//js
function f() {
const VARIABLE =10;
console.log(VARIABLE); // 输出 10
VARIABLE =20; // 抛出类型错误
console.log(VARIABLE);
}
总结
假如说在写前端页面中,碰到了要给一些button绑定一个事件,用for循环的时候就要当心,如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
</head>
<body>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<button>5</button>
<button>6</button>
</body>
<script>
var btn = document.getElementsByTagName('button');
for (var i = 0; i < btn.length; i++) {
btn[i].onclick = function () {
window.alert(i)//
}
}
</script>
</html>
结果就是,每一个button都会弹出6,而不是我们所愿的。
js中有闭包,可以通过闭包来解决问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
</head>
<body>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<button>5</button>
<button>6</button>
</body>
<script>
var btn = document.getElementsByTagName('button');
for (var i = 0; i < btn.length; i++) {
(function (i) {
btn[i].onclick = function () {
window.alert(i)
}
})(i)
}
</script>
</html>
但其实只要将var改成let就好了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo</title>
</head>
<body>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<button>5</button>
<button>6</button>
</body>
<script>
var btn = document.getElementsByTagName('button');
for (var i = 0; i < btn.length; i++) {
(function (i) {
btn[i].onclick = function () {
window.alert(i)
}
})(i)
}
</script>
</html>
所以,尽可能用const和let去替代var,为了规范!