Can you create a variable inside a function?

ts

Show

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 and

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

1 are two relatively new concepts for variable declarations in JavaScript. ,

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 is similar to

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3 in some respects, but allows users to avoid some of the common “gotchas” that users run into in JavaScript.

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

1 is an augmentation of

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 in that it prevents re-assignment to a variable.

With TypeScript being an extension of JavaScript, the language naturally supports

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 and

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

1. Here we’ll elaborate more on these new declarations and why they’re preferable to

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3.

If you’ve used JavaScript offhandedly, the next section might be a good way to refresh your memory. If you’re intimately familiar with all the quirks of

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3 declarations in JavaScript, you might find it easier to skip ahead.

tsfunction sumMatrix(matrix: number[][]) { var sum = 0; for (var i = 0; i < matrix.length; i++) { var currentRow = matrix[i]; for (var i = 0; i < currentRow.length; i++) { sum += currentRow[i]; } } return sum;}3 declarations

Declaring a variable in JavaScript has always traditionally been done with the

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3 keyword.

ts

var a = 10;

As you might’ve figured out, we just declared a variable named

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

2 with the value

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

3.

We can also declare a variable inside of a function:

ts

function f() {

var message = "Hello, world!";

return message;

}

and we can also access those same variables within other functions:

ts

function f() {

var a = 10;

return function g() {

var b = a + 1;

return b;

};

}

var g = f();

g(); // returns '11'

In this above example,

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

4 captured the variable

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

2 declared in

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

6. At any point that

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

4 gets called, the value of

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

2 will be tied to the value of

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

2 in

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

6. Even if

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

4 is called once

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

6 is done running, it will be able to access and modify

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

2.

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

Scoping rules

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3 declarations have some odd scoping rules for those used to other languages. Take the following example:

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

Some readers might do a double-take at this example. The variable

10 10 10 10 10 10 10 10 10 10

5 was declared within the

10 10 10 10 10 10 10 10 10 10

6 block, and yet we were able to access it from outside that block. That’s because

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3 declarations are accessible anywhere within their containing function, module, namespace, or global scope - all which we’ll go over later on - regardless of the containing block. Some people call this

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3-scoping or function-scoping. Parameters are also function scoped.

These scoping rules can cause several types of mistakes. One problem they exacerbate is the fact that it is not an error to declare the same variable multiple times:

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

Maybe it was easy to spot out for some experienced JavaScript developers, but the inner

10 10 10 10 10 10 10 10 10 10

9-loop will accidentally overwrite the variable

0 1 2 3 4 5 6 7 8 9

0 because

0 1 2 3 4 5 6 7 8 9

0 refers to the same function-scoped variable. As experienced developers know by now, similar sorts of bugs slip through code reviews and can be an endless source of frustration.

Variable capturing quirks

Take a quick second to guess what the output of the following snippet is:

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

For those unfamiliar,

0 1 2 3 4 5 6 7 8 9

2 will try to execute a function after a certain number of milliseconds (though waiting for anything else to stop running).

Ready? Take a look:

10 10 10 10 10 10 10 10 10 10

Many JavaScript developers are intimately familiar with this behavior, but if you’re surprised, you’re certainly not alone. Most people expect the output to be

0 1 2 3 4 5 6 7 8 9

Remember what we mentioned earlier about variable capturing? Every function expression we pass to

0 1 2 3 4 5 6 7 8 9

2 actually refers to the same

0 1 2 3 4 5 6 7 8 9

0 from the same scope.

Let’s take a minute to consider what that means.

0 1 2 3 4 5 6 7 8 9

2 will run a function after some number of milliseconds, but only after the

10 10 10 10 10 10 10 10 10 10

9 loop has stopped executing; By the time the

10 10 10 10 10 10 10 10 10 10

9 loop has stopped executing, the value of

0 1 2 3 4 5 6 7 8 9

0 is

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

3. So each time the given function gets called, it will print out

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

3!

A common work around is to use an IIFE - an Immediately Invoked Function Expression - to capture

0 1 2 3 4 5 6 7 8 9

0 at each iteration:

ts

for (var i = 0; i < 10; i++) {

// capture the current state of 'i'

// by invoking a function with its current value

(function (i) {

setTimeout(function () {

console.log(i);

}, 100 * i);

})(i);

}

This odd-looking pattern is actually pretty common. The

0 1 2 3 4 5 6 7 8 9

0 in the parameter list actually shadows the

0 1 2 3 4 5 6 7 8 9

0 declared in the

10 10 10 10 10 10 10 10 10 10

9 loop, but since we named them the same, we didn’t have to modify the loop body too much.

tsfunction sumMatrix(matrix: number[][]) { var sum = 0; for (var i = 0; i < matrix.length; i++) { var currentRow = matrix[i]; for (var i = 0; i < currentRow.length; i++) { sum += currentRow[i]; } } return sum;}0 declarations

By now you’ve figured out that

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3 has some problems, which is precisely why

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 statements were introduced. Apart from the keyword used,

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 statements are written the same way

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3 statements are.

ts

function f() {

var message = "Hello, world!";

return message;

}

0

The key difference is not in the syntax, but in the semantics, which we’ll now dive into.

Block-scoping

When a variable is declared using

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0, it uses what some call lexical-scoping or block-scoping. Unlike variables declared with

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3 whose scopes leak out to their containing function, block-scoped variables are not visible outside of their nearest containing block or

10 10 10 10 10 10 10 10 10 10

9-loop.

ts

function f() {

var message = "Hello, world!";

return message;

}

1

Here, we have two local variables

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

2 and

ts

function f() {

var message = "Hello, world!";

return message;

}

04.

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

2’s scope is limited to the body of

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

6 while

ts

function f() {

var message = "Hello, world!";

return message;

}

04’s scope is limited to the containing

10 10 10 10 10 10 10 10 10 10

6 statement’s block.

Variables declared in a

ts

function f() {

var message = "Hello, world!";

return message;

}

09 clause also have similar scoping rules.

ts

function f() {

var message = "Hello, world!";

return message;

}

2

Another property of block-scoped variables is that they can’t be read or written to before they’re actually declared. While these variables are “present” throughout their scope, all points up until their declaration are part of their temporal dead zone. This is just a sophisticated way of saying you can’t access them before the

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 statement, and luckily TypeScript will let you know that.

ts

function f() {

var message = "Hello, world!";

return message;

}

3

Something to note is that you can still capture a block-scoped variable before it’s declared. The only catch is that it’s illegal to call that function before the declaration. If targeting ES2015, a modern runtime will throw an error; however, right now TypeScript is permissive and won’t report this as an error.

ts

function f() {

var message = "Hello, world!";

return message;

}

4

For more information on temporal dead zones, see relevant content on the .

Re-declarations and Shadowing

With

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3 declarations, we mentioned that it didn’t matter how many times you declared your variables; you just got one.

ts

function f() {

var message = "Hello, world!";

return message;

}

5

In the above example, all declarations of

10 10 10 10 10 10 10 10 10 10

5 actually refer to the same

10 10 10 10 10 10 10 10 10 10

5, and this is perfectly valid. This often ends up being a source of bugs. Thankfully,

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 declarations are not as forgiving.

ts

function f() {

var message = "Hello, world!";

return message;

}

6

The variables don’t necessarily need to both be block-scoped for TypeScript to tell us that there’s a problem.

ts

function f() {

var message = "Hello, world!";

return message;

}

7

That’s not to say that a block-scoped variable can never be declared with a function-scoped variable. The block-scoped variable just needs to be declared within a distinctly different block.

ts

function f() {

var message = "Hello, world!";

return message;

}

8

The act of introducing a new name in a more nested scope is called shadowing. It is a bit of a double-edged sword in that it can introduce certain bugs on its own in the event of accidental shadowing, while also preventing certain bugs. For instance, imagine we had written our earlier

ts

function f() {

var message = "Hello, world!";

return message;

}

15 function using

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 variables.

ts

function f() {

var message = "Hello, world!";

return message;

}

9

This version of the loop will actually perform the summation correctly because the inner loop’s

0 1 2 3 4 5 6 7 8 9

0 shadows

0 1 2 3 4 5 6 7 8 9

0 from the outer loop.

Shadowing should usually be avoided in the interest of writing clearer code. While there are some scenarios where it may be fitting to take advantage of it, you should use your best judgement.

Block-scoped variable capturing

When we first touched on the idea of variable capturing with

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

3 declaration, we briefly went into how variables act once captured. To give a better intuition of this, each time a scope is run, it creates an “environment” of variables. That environment and its captured variables can exist even after everything within its scope has finished executing.

ts

function f() {

var a = 10;

return function g() {

var b = a + 1;

return b;

};

}

var g = f();

g(); // returns '11'

0

Because we’ve captured

ts

function f() {

var message = "Hello, world!";

return message;

}

20 from within its environment, we’re still able to access it despite the fact that the

10 10 10 10 10 10 10 10 10 10

6 block finished executing.

Recall that with our earlier

0 1 2 3 4 5 6 7 8 9

2 example, we ended up needing to use an IIFE to capture the state of a variable for every iteration of the

10 10 10 10 10 10 10 10 10 10

9 loop. In effect, what we were doing was creating a new variable environment for our captured variables. That was a bit of a pain, but luckily, you’ll never have to do that again in TypeScript.

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 declarations have drastically different behavior when declared as part of a loop. Rather than just introducing a new environment to the loop itself, these declarations sort of create a new scope per iteration. Since this is what we were doing anyway with our IIFE, we can change our old

0 1 2 3 4 5 6 7 8 9

2 example to just use a

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 declaration.

ts

function f() {

var a = 10;

return function g() {

var b = a + 1;

return b;

};

}

var g = f();

g(); // returns '11'

1

and as expected, this will print out

0 1 2 3 4 5 6 7 8 9

tsfunction sumMatrix(matrix: number[][]) { var sum = 0; for (var i = 0; i < matrix.length; i++) { var currentRow = matrix[i]; for (var i = 0; i < currentRow.length; i++) { sum += currentRow[i]; } } return sum;}1 declarations

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

1 declarations are another way of declaring variables.

ts

function f() {

var a = 10;

return function g() {

var b = a + 1;

return b;

};

}

var g = f();

g(); // returns '11'

3

They are like

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 declarations but, as their name implies, their value cannot be changed once they are bound. In other words, they have the same scoping rules as

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0, but you can’t re-assign to them.

This should not be confused with the idea that the values they refer to are immutable.

ts

function f() {

var a = 10;

return function g() {

var b = a + 1;

return b;

};

}

var g = f();

g(); // returns '11'

4

Unless you take specific measures to avoid it, the internal state of a

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

1 variable is still modifiable. Fortunately, TypeScript allows you to specify that members of an object are

ts

function f() {

var message = "Hello, world!";

return message;

}

32. The chapter on Interfaces has the details.

tsfunction sumMatrix(matrix: number[][]) { var sum = 0; for (var i = 0; i < matrix.length; i++) { var currentRow = matrix[i]; for (var i = 0; i < currentRow.length; i++) { sum += currentRow[i]; } } (adsbygoogle = window.adsbygoogle || []).push({}); return sum;}0 vs. tsfunction sumMatrix(matrix: number[][]) { var sum = 0; for (var i = 0; i < matrix.length; i++) { var currentRow = matrix[i]; for (var i = 0; i < currentRow.length; i++) { sum += currentRow[i]; } } return sum;}1

Given that we have two types of declarations with similar scoping semantics, it’s natural to find ourselves asking which one to use. Like most broad questions, the answer is: it depends.

Applying the principle of least privilege, all declarations other than those you plan to modify should use

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

1. The rationale is that if a variable didn’t need to get written to, others working on the same codebase shouldn’t automatically be able to write to the object, and will need to consider whether they really need to reassign to the variable. Using

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

1 also makes code more predictable when reasoning about flow of data.

Use your best judgement, and if applicable, consult the matter with the rest of your team.

The majority of this handbook uses

ts

function sumMatrix(matrix: number[][]) {

var sum = 0;

for (var i = 0; i < matrix.length; i++) {

var currentRow = matrix[i];

for (var i = 0; i < currentRow.length; i++) {

sum += currentRow[i];

}

}

return sum;

}

0 declarations.

Destructuring

Another ECMAScript 2015 feature that TypeScript has is destructuring. For a complete reference, see the article on the Mozilla Developer Network. In this section, we’ll give a short overview.

Array destructuring

The simplest form of destructuring is array destructuring assignment:

ts

function f() {

var a = 10;

return function g() {

var b = a + 1;

return b;

};

}

var g = f();

g(); // returns '11'

5

This creates two new variables named

ts

function f() {

var message = "Hello, world!";

return message;

}

38 and

ts

function f() {

var message = "Hello, world!";

return message;

}

39. This is equivalent to using indexing, but is much more convenient:

ts

function f() {

var a = 10;

return function g() {

var b = a + 1;

return b;

};

}

var g = f();

g(); // returns '11'

6

Destructuring works with already-declared variables as well:

ts

function f() {

var a = 10;

return function g() {

var b = a + 1;

return b;

};

}

var g = f();

g(); // returns '11'

7

And with parameters to a function:

ts

function f() {

var a = 10;

return function g() {

var b = a + 1;

return b;

};

}

var g = f();

g(); // returns '11'

8

You can create a variable for the remaining items in a list using the syntax

ts

function f() {

var message = "Hello, world!";

return message;

}

40:

ts

function f() {

var a = 10;

return function g() {

var b = a + 1;

return b;

};

}

var g = f();

g(); // returns '11'

9

Of course, since this is JavaScript, you can just ignore trailing elements you don’t care about:

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

0

Or other elements:

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

1

Tuple destructuring

Tuples may be destructured like arrays; the destructuring variables get the types of the corresponding tuple elements:

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

2

It’s an error to destructure a tuple beyond the range of its elements:

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

3

As with arrays, you can destructure the rest of the tuple with

ts

function f() {

var message = "Hello, world!";

return message;

}

40, to get a shorter tuple:

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

4

Or ignore trailing elements, or other elements:

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

5

Object destructuring

You can also destructure objects:

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

6

This creates new variables

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

2 and

ts

function f() {

var message = "Hello, world!";

return message;

}

04 from

ts

function f() {

var message = "Hello, world!";

return message;

}

44 and

ts

function f() {

var message = "Hello, world!";

return message;

}

45. Notice that you can skip

ts

function f() {

var message = "Hello, world!";

return message;

}

46 if you don’t need it.

Like array destructuring, you can have assignment without declaration:

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

7

Notice that we had to surround this statement with parentheses. JavaScript normally parses a

ts

function f() {

var message = "Hello, world!";

return message;

}

47 as the start of block.

You can create a variable for the remaining items in an object using the syntax

ts

function f() {

var message = "Hello, world!";

return message;

}

40:

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

8

Property renaming

You can also give different names to properties:

ts

function f() {

var a = 1;

a = 2;

var b = g();

a = 3;

return b;

function g() {

return a;

}

}

f(); // returns '2'

9

Here the syntax starts to get confusing. You can read

ts

function f() {

var message = "Hello, world!";

return message;

}

49 as ”

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

2 as

ts

function f() {

var message = "Hello, world!";

return message;

}

51”. The direction is left-to-right, as if you had written:

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

0

Confusingly, the colon here does not indicate the type. The type, if you specify it, still needs to be written after the entire destructuring:

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

1

Default values

Default values let you specify a default value in case a property is undefined:

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

2

In this example the

ts

function f() {

var message = "Hello, world!";

return message;

}

52 indicates that

ts

function f() {

var message = "Hello, world!";

return message;

}

04 is optional, so it may be

ts

function f() {

var message = "Hello, world!";

return message;

}

54.

ts

function f() {

var message = "Hello, world!";

return message;

}

55 now has a variable for

ts

function f() {

var message = "Hello, world!";

return message;

}

56 as well as the properties

ts

for (var i = 0; i < 10; i++) {

setTimeout(function () {

console.log(i);

}, 100 * i);

}

2 and

ts

function f() {

var message = "Hello, world!";

return message;

}

04, even if

ts

function f() {

var message = "Hello, world!";

return message;

}

04 is undefined.

Function declarations

Destructuring also works in function declarations. For simple cases this is straightforward:

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

3

But specifying defaults is more common for parameters, and getting defaults right with destructuring can be tricky. First of all, you need to remember to put the pattern before the default value.

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

4

The snippet above is an example of type inference, explained earlier in the handbook.

Then, you need to remember to give a default for optional properties on the destructured property instead of the main initializer. Remember that

ts

function f() {

var message = "Hello, world!";

return message;

}

60 was defined with

ts

function f() {

var message = "Hello, world!";

return message;

}

04 optional:

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

5

Use destructuring with care. As the previous example demonstrates, anything but the simplest destructuring expression is confusing. This is especially true with deeply nested destructuring, which gets really hard to understand even without piling on renaming, default values, and type annotations. Try to keep destructuring expressions small and simple. You can always write the assignments that destructuring would generate yourself.

Spread

The spread operator is the opposite of destructuring. It allows you to spread an array into another array, or an object into another object. For example:

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

6

This gives bothPlus the value

ts

function f() {

var message = "Hello, world!";

return message;

}

62. Spreading creates a shallow copy of

ts

function f() {

var message = "Hello, world!";

return message;

}

38 and

ts

function f() {

var message = "Hello, world!";

return message;

}

39. They are not changed by the spread.

You can also spread objects:

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

7

Now

ts

function f() {

var message = "Hello, world!";

return message;

}

65 is

ts

function f() {

var message = "Hello, world!";

return message;

}

66. Object spreading is more complex than array spreading. Like array spreading, it proceeds from left-to-right, but the result is still an object. This means that properties that come later in the spread object overwrite properties that come earlier. So if we modify the previous example to spread at the end:

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

8

Then the

ts

function f() {

var message = "Hello, world!";

return message;

}

67 property in

ts

function f() {

var message = "Hello, world!";

return message;

}

68 overwrites

ts

function f() {

var message = "Hello, world!";

return message;

}

69, which is not what we want in this case.

Object spread also has a couple of other surprising limits. First, it only includes an objects’ own, enumerable properties. Basically, that means you lose methods when you spread instances of an object:

ts

function f(shouldInitialize: boolean) {

if (shouldInitialize) {

var x = 10;

}

return x;

}

f(true); // returns '10'

f(false); // returns 'undefined'

9

Second, the TypeScript compiler doesn’t allow spreads of type parameters from generic functions. That feature is expected in future versions of the language.

Can you put a variable inside a function?

Variables defined inside functions are called local variables. Their value can only be used within the function where they are declared. You can change the scope of a local variable using the global keyword – which we'll discuss in the next section.

Can you create a variable inside the function in JavaScript?

JavaScript has function scope: Each function creates a new scope. Variables defined inside a function are not accessible (visible) from outside the function. Variables declared with var , let and const are quite similar when declared inside a function.

How do you add a variable to a function?

we put the function in a variable if inside the function block we use the return method: var multiplyTwo = function (a) { return a * 2; }; if we simply call this function, nothing will be printed, although nothing is wrong with the writing of the function itself.