2018-10-10 18:03:03 -04:00
|
|
|
|
---
|
|
|
|
|
id: 587d7b87367417b2b2512b40
|
2020-12-16 00:37:30 -07:00
|
|
|
|
title: 比较 var 和 let 关键字的作用域
|
2018-10-10 18:03:03 -04:00
|
|
|
|
challengeType: 1
|
2020-08-04 15:13:35 +08:00
|
|
|
|
forumTopicId: 301195
|
2021-01-13 03:31:00 +01:00
|
|
|
|
dashedName: compare-scopes-of-the-var-and-let-keywords
|
2018-10-10 18:03:03 -04:00
|
|
|
|
---
|
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
# --description--
|
|
|
|
|
|
|
|
|
|
当你使用`var`关键字来声明一个变量的时候,这个变量会被声明成全局变量,或是函数内的局部变量。
|
|
|
|
|
|
|
|
|
|
`let`关键字的作用类似,但会有一些额外的特性。如果你在代码块、语句或表达式中使用关键字`let`声明变量,这个变量的作用域就被限制在当前的代码块,语句或表达式之中。
|
|
|
|
|
|
2020-08-04 15:13:35 +08:00
|
|
|
|
举个例子:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
var numArray = [];
|
|
|
|
|
for (var i = 0; i < 3; i++) {
|
|
|
|
|
numArray.push(i);
|
|
|
|
|
}
|
|
|
|
|
console.log(numArray);
|
|
|
|
|
// 返回 [0, 1, 2]
|
|
|
|
|
console.log(i);
|
|
|
|
|
// 返回 3
|
|
|
|
|
```
|
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
当使用`var`关键字的时候,`i`会被声明成全局变量。当`i++`执行的时候,它会改变全局变量的值。这段代码可以看做下面这样:
|
2020-08-04 15:13:35 +08:00
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
var numArray = [];
|
|
|
|
|
var i;
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
|
numArray.push(i);
|
|
|
|
|
}
|
|
|
|
|
console.log(numArray);
|
|
|
|
|
// 返回 [0, 1, 2]
|
|
|
|
|
console.log(i);
|
|
|
|
|
// 返回 3
|
|
|
|
|
```
|
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
如果你在`for`循环中创建了使用`i`变量的函数,那么在后续调用函数的时候,上面提到的这种行为就会出现问题。这是因为函数存储的值会因为全局变量`i`的变化而不断的改变。
|
2020-08-04 15:13:35 +08:00
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
var printNumTwo;
|
|
|
|
|
for (var i = 0; i < 3; i++) {
|
|
|
|
|
if (i === 2) {
|
|
|
|
|
printNumTwo = function() {
|
|
|
|
|
return i;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
console.log(printNumTwo());
|
|
|
|
|
// 返回 3
|
|
|
|
|
```
|
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
可以看到,`printNumTwo()`打印了 3 而不是 2。这是因为`i`发生了改变,并且函数`printNumTwo()`返回的是全局变量`i`的值,而不是`for`循环中创建函数时`i`的值。`let`关键字就不会有这种现象:
|
2020-08-04 15:13:35 +08:00
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
'use strict';
|
|
|
|
|
let printNumTwo;
|
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
|
|
|
if (i === 2) {
|
|
|
|
|
printNumTwo = function() {
|
|
|
|
|
return i;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
console.log(printNumTwo());
|
|
|
|
|
// 返回 2
|
|
|
|
|
console.log(i);
|
|
|
|
|
// 返回 "i 未定义"
|
|
|
|
|
```
|
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
`i`在全局作用域中没有声明,所以它没有被定义,它的声明只会发生在`for`循环内。在循环执行的时候,`let`关键字创建了三个不同的`i`变量,他们的值分别为 0、1 和 2,所以`printNumTwo()`返回了正确的值。
|
2018-10-10 18:03:03 -04:00
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
# --instructions--
|
2018-10-10 18:03:03 -04:00
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
修改这段代码,使得在`if`语句中声明的`i`变量与在函数的第一行声明的`i`变量是彼此独立的。请注意不要在你的代码的任何地方使用`var`关键字。
|
2018-10-10 18:03:03 -04:00
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
这个练习说明了使用`var`与`let`关键字声明变量时,作用域之间的不同。当编写类似这个练习中的函数的时候,通常来说最好还是使用不同的变量名来避免误会。
|
2018-10-10 18:03:03 -04:00
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
# --hints--
|
2018-10-10 18:03:03 -04:00
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
`var`不应该在代码中存在。
|
2018-10-10 18:03:03 -04:00
|
|
|
|
|
|
|
|
|
```js
|
2020-12-16 00:37:30 -07:00
|
|
|
|
(getUserInput) => assert(!getUserInput('index').match(/var/g));
|
2018-10-10 18:03:03 -04:00
|
|
|
|
```
|
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
在`if`语句中声明的`i`变量的值是 'block scope'。
|
2018-10-10 18:03:03 -04:00
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
```js
|
|
|
|
|
(getUserInput) =>
|
|
|
|
|
assert(
|
|
|
|
|
getUserInput('index').match(/(i\s*=\s*).*\s*.*\s*.*\1('|")block\s*scope\2/g)
|
|
|
|
|
);
|
|
|
|
|
```
|
2018-10-10 18:03:03 -04:00
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
`checkScope()`应当返回 'function scope'
|
2018-10-10 18:03:03 -04:00
|
|
|
|
|
|
|
|
|
```js
|
2020-12-16 00:37:30 -07:00
|
|
|
|
assert(checkScope() === 'function scope');
|
2018-10-10 18:03:03 -04:00
|
|
|
|
```
|
2020-08-04 15:13:35 +08:00
|
|
|
|
|
2021-01-13 03:31:00 +01:00
|
|
|
|
# --seed--
|
|
|
|
|
|
|
|
|
|
## --seed-contents--
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
function checkScope() {
|
|
|
|
|
var i = 'function scope';
|
|
|
|
|
if (true) {
|
|
|
|
|
i = 'block scope';
|
|
|
|
|
console.log('Block scope i is: ', i);
|
|
|
|
|
}
|
|
|
|
|
console.log('Function scope i is: ', i);
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2020-12-16 00:37:30 -07:00
|
|
|
|
# --solutions--
|
|
|
|
|
|
2021-01-13 03:31:00 +01:00
|
|
|
|
```js
|
|
|
|
|
function checkScope() {
|
|
|
|
|
let i = 'function scope';
|
|
|
|
|
if (true) {
|
|
|
|
|
let i = 'block scope';
|
|
|
|
|
console.log('Block scope i is: ', i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('Function scope i is: ', i);
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
```
|