官术网_书友最值得收藏!

Function scope and hoisting

Low-level languages, such as C, have low-level memory management features. In programming languages with a higher level of abstraction, such as TypeScript, values are allocated when variables are created, and automatically cleared from memory when they are no longer used. The process that cleans the memory is known as garbage collection and is performed by the JavaScript runtime garbage collector.

The garbage collector does a great job, but it is a mistake to assume that it will always prevent us from facing a memory leak. The garbage collector will clear a variable from the memory whenever the variable is out of scope. It is important to understand how the TypeScript scope works in order for us to understand the life cycle of variables.

Some programming languages use the structure of the program source code to determine what variables we are referring to (lexical scoping), while others use the runtime state of the program stack to determine what variable we are referring to (dynamic scoping). Most modern programming languages use lexical scoping (including TypeScript). Lexical scoping tends to be dramatically easier to understand for both humans and analysis tools than dynamic scoping.

While, in most lexical-scoped programming languages, variables are scoped to a block (a section of code delimited by curly braces {}), in TypeScript (and JavaScript) variables are scoped to a function, as demonstrated by the following code snippet:

function foo(): void {
if (true) {
var bar: number = 0;
}
console.log(bar);
}

foo(); // 0

The preceding function, named foo, contains an if structure. We have declared a numeric variable named bar inside the if statement, and later we have attempted to show the value of the bar variable using the log function.

We might think that the preceding code sample would throw an error in the fifth line because the bar variable should be out of scope when the log function is invoked. However, if we invoke the foo function, the log function will be able to display the variable bar without errors because all variables inside a function will be within the scope of the entire function body, even if they are inside another block of code (except a function block).

The following diagram displays the lexical scope at the function level (left), and the lexical scope at the block level (right). As we can see, there is only one function, but there are two blocks:

The preceding code snippet might seem confusing, but it is easy to understand once we know that, at runtime, all the variable declarations are moved to the top of a function before the function is executed. This behavior is known as hoisting.

TypeScript is compiled to JavaScript and then executed—this means that a TypeScript application is a JavaScript application at runtime and, for this reason, when we refer to the TypeScript runtime, we are talking about the JavaScript runtime. We will learn in depth about the runtime in Chapter 4, The Runtime – The Event Loop and The this Operator, and Chapter 5, The Runtime – Closures and Prototypes.

Before the preceding code snippet is executed, the runtime will move the declaration of the bar variable to the top of our function:

function foo() {
var bar;
if (true) {
bar = 0;
}
console.log(bar);
}

foo(); // 0

This explains why it is possible to use a variable before it is declared. Let's look at an example:

function foo(): void {
bar = 0;
var bar: number;
console.log(bar);
}

foo(); // 0

In the preceding code snippet, we have declared a function, foo, and, in its body, we have assigned the value 0 to a variable named bar. At this point, the variable has not been declared. In the second line, we are declaring the bar variable and its type. In the last line, we are displaying the value of the bar variable using the alert function.

Since declaring a variable anywhere inside a function (except another function) is equivalent to declaring it at the top of the function, the foo function is transformed into the following at runtime:

function foo(): void {
var bar: number;
bar = 0;
console.log(bar);
}

foo(); // 0

Developers with a background in programming languages with block scope, such as Java or C#, are not used to function scope and it is one of the most criticized characteristics of JavaScript. The people in charge of the development of the ECMAScript 6 specification are aware of this, and, as a result, they have introduced the keywords let and const.

The let keyword allows us to set the scope of a variable to a block (if, while, for, and so on) rather than a function. We can update the first example in this section to showcase how the let keyword works:

function foo(): void {
if (true) {
let bar: number = 0;
bar = 1;
}
console.log(bar); // Error
}

The bar variable is now declared using the let keyword, and, as a result, it is only accessible inside the if block. The variable is not hoisted to the top of the foo function and cannot be accessed by the alert function outside the if statement.

While variables defined with const follow the same scope rules as variables declared with let, they can't be reassigned:

function foo(): void {
if (true) {
const bar: number = 0;
bar = 1; // Error
}
alert(bar); // Error
}

If we attempt to compile the preceding code snippet, we will get an error because the bar variable is not accessible outside the if statement (just like when we used the let keyword), and a new error occurs when we try to assign a new value to the bar variable. The second error is caused because it is not possible to assign a new value to a constant variable once the variable has already been initialized.

Variables declared with the const keyword cannot be reassigned, but are not immutable. When we say that a variable is immutable, we mean that it cannot be modified. We will learn more about immutability in Chapter 9, Functional-Reactive Programming.

主站蜘蛛池模板: 永川市| 石嘴山市| 三河市| 永寿县| 靖边县| 克东县| 桐城市| 奇台县| 香河县| 青阳县| 乌兰浩特市| 宜阳县| 绍兴县| 阿拉善盟| 德江县| 阜南县| 渭源县| 南通市| 凤山县| 扎鲁特旗| 清镇市| 宝坻区| 舒城县| 东兰县| 福建省| 商城县| 许昌县| 工布江达县| 科技| 龙泉市| 南京市| 昌图县| 图片| 宜兰市| 通海县| 合作市| 东莞市| 鹤峰县| 桐柏县| 个旧市| 衡南县|