var,let,const的区别

人总是喜欢自己没有的

一个有趣的现象

let

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
<script>
var lis = document.querySelectorAll("li");
for (let i=0; i< lis.length; i++) {
var li = document.querySelectorAll("li")[i];
li.onclick = function () {
alert(i);
}
}
// 依次点击5个元素, 分别弹出0,1,2,3,4,5
</script>

var

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
<script>
var lis = document.querySelectorAll("li");
for (var i=0; i< lis.length; i++) {
var li = document.querySelectorAll("li")[i];
li.onclick = function () {
alert(i);
}
}
// 依次点击5个元素, 分别弹出5,5,5,5,5,5
</script>

问题

在不使用let的情况下, 如何使点击每个li弹出对应的序号
事件委托
事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown……)的函数委托到另一个元素;
一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<ul id="list">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
<script>
document.getElementById('list').addEventListener('click', function (e) {
// 兼容性处理
var event = e || window.event;
var target = event.target || event.srcElement;
// 判断是否匹配目标元素
if (target.nodeName.toLocaleLowerCase() === 'li') {
console.log('the content is: ', target.innerHTML);
}
});
</script>

let

let定义变量时和var有两个区别:块级作用域、不会变量提升和不能定义在块中已有标识符同名的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getValue(condition) {

if (condition) {
let value = "blue";

// other code

return value;
} else {

// value doesn't exist here

return null;
}

// value doesn't exist here
}

当用let定义value时,我们只能在if里面才能访问到value了,value变量也不会变量提升,从而我们在else里面不能访问到value。
let最常用的场景应该是for循环了:

1
2
for (let i = 0; i < len; i++) {
}

块级作用域
块级作用域就不用多说,就是用let定义的变量只在定义它的块中有效,出了这个块你就不能访问到它了。
变量提升
变量提升应该是在面试的时候会经常考到,例如:

1
2
3
4
5
6
7
8
9
<script>
function test () {
console.log(value);
var value = 'something';
console.log(value);
}
test();
// 结果: undefined something
</script>

我们用let重新定义上面的test()函数:

1
2
3
4
5
6
7
8
9
<script>
function test () {
console.log(value);
let value = 'something';
console.log(value);
}
test();
// 结果程序直接报错:Uncaught ReferenceError: value is not defined
</script>

同名变量
用var定义变量时,我们可以多次对它进行定义,例如:

1
2
3
var a = 1;
var a = 2;
var a = 3;

这样的代码是不会报错的,在let定义的相同块中定义同名变量时就会报错了,例如:

1
2
3
4
5
6
7
let a = 1;
let a = 2;

// or
var a = 1;
let a = 2;

要注意的是要与let定义时在相同的块中,下面的代码是不会出错的:

1
2
3
4
var a = 1;
if (something) {
let a = 2;
}

var

我们知道在ES6之前,是没有块级作用域这一说的,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getValue(condition) {

if (condition) {
var value = "blue";

// other code

return value;
} else {

// value exists here with a value of undefined

return null;
}

// value exists here with a value of undefined
}

你可能会觉得在else里面无法访问到value变量,其实在js内部会造成变量提升,这意味着我们可以在else里面访问到value变量,只是它未初始化,所以其变量值为undefined。实际解析时代码可能像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getValue(condition) {

var value;

if (condition) {
value = "blue";

// other code

return value;
} else {

return null;
}
}

var会造成变量提升

const

const除了具有let的块级作用域和不会变量提升外,还有就是它定义的是常量,在用const定义变量后,我们就不能修改它了,对变量的修改会默默的失败(在iojs中会抛出异常,在Chrome下会默默的失败)。例如:

1
2
3
4
const PI = 3.1415;
console.log(PI);
PI = 22;
console.log(PI);

http://cookfront.github.io/2015/05/28/es6-let-const/