This commit is contained in:
Ilya Kantor 2017-03-21 17:14:05 +03:00
parent ab9ab64bd5
commit 97c8f22bbb
289 changed files with 195 additions and 172 deletions

View file

@ -605,172 +605,3 @@ This feature of V8 is good to know. If you are debugging with Chrome/Opera, soon
That is not a bug of debugger, but a special feature of V8. Maybe it will be changed sometimes. That is not a bug of debugger, but a special feature of V8. Maybe it will be changed sometimes.
You always can check for it by running examples on this page. You always can check for it by running examples on this page.
``` ```
## The old "var"
In the very first chapter about [variables](info:variables), we mentioned three ways of variable declaration:
1. `let`
2. `const`
3. `var`
`let` and `const` behave exactly the same way in terms of Lexical Environments.
But `var` is a very different beast, that originates from very old times. It's generally not used in modern scripts, but still lurks in the old ones. If you don't plan meeting such scripts you may even skip this subsection or postpone reading it, but then there's a chance that it bites you some time.
From the first sight, `var` behaves similar to `let`. That is, declares a variable:
```js run
function sayHi() {
let phrase = "Hello"; // local variable, "var" instead of "let"
alert(phrase); // Hello
}
sayHi();
alert(phrase); // Error, phrase is not defined
```
...But here are the differences.
`var` variables are either funciton-wide or global, they are visible through blocks.
: For instance:
```js
if (true) {
let test = true; // use "var" instead of "let"
}
*!*
alert(test); // true, the variable lives after if
*/!*
```
If we used `let test` on the 2nd line, then it wouldn't be visible to `alert`. But `var` ignores code blocks, so we've got a global `test`.
The same thing for loops: `var` can not be block or loop-local:
```js
for(let i = 0; i < 10; i++) {
// ...
}
*!*
alert(i); // 10, "i" is visible after loop, it's a global variable
*/!*
```
If a code block in inside a function, then `var` becomes a function-level variable:
```js
function sayHi() {
if (true) {
let phrase = "Hello";
}
alert(phrase); // works
}
sayHi();
alert(phrase); // Error: phrase is not defined
```
As we can see, `var` pierces through `if`, `for` or other code blocks. That's because long time ago in JavaScript blocks had no Lexical Environments. And `var` is a reminiscence of that.
`var` declarations are processed when the function starts (or script starts for globals).
: In other words, `var` variables are defined from the beginning of the function.
So this code:
```js
function sayHi() {
phrase = "Hello";
alert(phrase);
*!*
let phrase;
*/!*
}
```
...Is technically the same as this:
```js
function sayHi() {
*!*
let phrase;
*/!*
phrase = "Hello";
alert(phrase);
}
```
...Or even as this (remember, code blocks are ignored):
```js
function sayHi() {
phrase = "Hello";
*!*
if (false) {
let phrase;
}
*/!*
alert(phrase);
}
```
People also call such behavior "hoisting" (raising), because all `var` are "hoisted" (raised) to the top of the function.
So in the example above, `if (false)` branch never executes, but that doesn't matter. The `var` inside it is processed in the beginning of the function.
**The important thing is that declarations are hoisted, but assignments are not.**
For instance:
```js run
function sayHi() {
alert(phrase);
*!*
let phrase = "Hello";
*/!*
}
sayHi();
```
The line `let phrase = "Hello"` has two actions in it: variable declaration `var` and assignment `=`.
The declaration is processed at the start of function execution (hoisted), but the assignment is not. So the code works essentially like this:
```js run
function sayHi() {
*!*
let phrase; // variable is declared from the top...
*/!*
alert(phrase); // undefined
*!*
phrase = "Hello"; // ...but assigned when the execution reaches this line.
*/!*
}
sayHi();
```
**In other words, all `var` variables exist, but are `undefined` at the beginning of a function.**
They are assigned later as the execution reaches assignments.
In the example above, `alert` runs without an error, because the variable `phrase` exists. But its value is not yet assigned, so it shows `undefined`.
```warn header="Why we should not use `var`"
Special behaviors of described in this section make using `var` inconvenient most of time. First, we can't create block-local variables. And hoisting just creates more space for errors. So, once again, for new scripts `var` is used exceptionally rarely.
```

View file

@ -0,0 +1,187 @@
# The old "var"
In the very first chapter about [variables](info:variables), we mentioned three ways of variable declaration:
1. `let`
2. `const`
3. `var`
`let` and `const` behave exactly the same way in terms of Lexical Environments.
But `var` is a very different beast, that originates from very old times. It's generally not used in modern scripts, but still lurks in the old ones.
If you don't plan meeting such scripts you may even skip this chapter or postpone it, but then there's a chance that it bites you later.
[cut]
From the first sight, `var` behaves similar to `let`. That is, declares a variable:
```js run
function sayHi() {
var phrase = "Hello"; // local variable, "var" instead of "let"
alert(phrase); // Hello
}
sayHi();
alert(phrase); // Error, phrase is not defined
```
...But here are the differences.
## "var" has no block scope
`var` variables are either function-wide or global, they are visible through blocks.
For instance:
```js
if (true) {
var test = true; // use "var" instead of "let"
}
*!*
alert(test); // true, the variable lives after if
*/!*
```
If we used `let test` on the 2nd line, then it wouldn't be visible to `alert`. But `var` ignores code blocks, so we've got a global `test`.
The same thing for loops: `var` can not be block or loop-local:
```js
for(var i = 0; i < 10; i++) {
// ...
}
*!*
alert(i); // 10, "i" is visible after loop, it's a global variable
*/!*
```
If a code block in inside a function, then `var` becomes a function-level variable:
```js
function sayHi() {
if (true) {
var phrase = "Hello";
}
alert(phrase); // works
}
sayHi();
alert(phrase); // Error: phrase is not defined
```
As we can see, `var` pierces through `if`, `for` or other code blocks. That's because long time ago in JavaScript blocks had no Lexical Environments. And `var` is a reminiscence of that.
## "var" are processed at the function start
`var` declarations are processed when the function starts (or script starts for globals).
In other words, `var` variables are defined from the beginning of the function, no matter where the definition is (assuming that the definition is not in the nested function).
So this code:
```js
function sayHi() {
phrase = "Hello";
alert(phrase);
*!*
var phrase;
*/!*
}
```
...Is technically the same as this (moved `var phrase` above):
```js
function sayHi() {
*!*
var phrase;
*/!*
phrase = "Hello";
alert(phrase);
}
```
...Or even as this (remember, code blocks are ignored):
```js
function sayHi() {
phrase = "Hello"; // (*)
*!*
if (false) {
var phrase;
}
*/!*
alert(phrase);
}
```
People also call such behavior "hoisting" (raising), because all `var` are "hoisted" (raised) to the top of the function.
So in the example above, `if (false)` branch never executes, but that doesn't matter. The `var` inside it is processed in the beginning of the function, so at the moment of `(*)` there variable exists.
**Declarations are hoisted, but assignments are not.**
That's better to demonstrate with an example, like this:
```js run
function sayHi() {
alert(phrase);
*!*
var phrase = "Hello";
*/!*
}
sayHi();
```
The line `var phrase = "Hello"` has two actions in it:
1. Variable declaration `var`
2. Variable assignment `=`.
The declaration is processed at the start of function execution ("hoisted"), but the assignment always works at the place where it is. So the code works essentially like this:
```js run
function sayHi() {
*!*
var phrase; // declaration works at the start...
*/!*
alert(phrase); // undefined
*!*
phrase = "Hello"; // ...assignment - when the execution reaches it.
*/!*
}
sayHi();
```
Because all `var` declarations are processed at the function start, we can reference them at any place. But variables are undefined until the assignments.
In both examples above `alert` runs without an error, because the variable `phrase` exists. But its value is not yet assigned, so it shows `undefined`.
## Summary
There are two main differences of `var`:
1. Variables have no block scope, they are visible minimum at the function level.
2. Variable declarations are processed at function start.
There's one more minor difference related to the global object, we'll cover that in the next chapter.
These differences are actually a bad thing most of time. First, we can't create block-local variables. And hoisting just creates more space for errors. So, for new scripts `var` is used exceptionally rarely.

View file

@ -28,7 +28,7 @@ It does two things:
<!-- no-strict to move variables out of eval --> <!-- no-strict to move variables out of eval -->
```js untrusted run no-strict refresh ```js untrusted run no-strict refresh
let phrase = "Hello"; var phrase = "Hello";
function sayHi() { function sayHi() {
alert(phrase); alert(phrase);
@ -75,10 +75,10 @@ Usually, it's not a good idea to use it, but here are some examples you can meet
1. To access exactly the global variable if the function has the local one with the same name. 1. To access exactly the global variable if the function has the local one with the same name.
```js untrusted run no-strict refresh ```js untrusted run no-strict refresh
let user = "Global"; var user = "Global";
function sayHi() { function sayHi() {
let user = "Local"; var user = "Local";
*!* *!*
alert(window.user); // Global alert(window.user); // Global

Some files were not shown because too many files have changed in this diff Show more