JavaScript scopes and closures

Source: Internet
Author: User
Tags closure function definition

In this article, I will introduce the following concepts in popular language and simple code:

    • Variable Promotion
    • Usage scenarios for this
    • Scope
    • Application of closures

Finally, there is an example of

Variable Promotion

First of all we need to know that JS execution order is from top to bottom, but this order, not entirely dependent on you, because JS in the existence of variable declaration elevation.

It's easier here, directly on the code.

Console.log (a)  //undefinedvar a =fn (' Zhangsan ')function  fn (name) {    =    console.log (name, age)  //Zhangsan    var age }

Results

When printing A, a does not declare, why not error, but print undefined.

FN does not declare when executing FN, why is the statement of FN executed?

This is the declaration elevation of variables, although the code is written like this, but in fact the order of execution is like this.

var a function FN (name) {        = = = +fn (' Zhangsan ')

JS will refer to all the declarations before, and then order to perform other operations such as assignment, because before printing a, there is already a variable, but there is no assignment, so will print out undefined, not an error, fn the same.

Notice the difference between the function declaration and the function expression. The FN in the previous example is a function declaration. Next, distinguish it by code.

FN1 (' abc ')function  fn1 (str) {    console.log (str)}fn2 (' def ')var  function(str) {    console.log (str)}

In this case, FN1 is a function declaration, and fn2 is a function expression. The function body in a function expression is not promoted.

Results

You can see that the FN1 has been promoted, and the function body of fn2 has not been promoted.

The effect is equal to

var fn2fn2 (' def 'function(str) {    console.log (str)}

This should understand why the error. The variable promotion says so much, next look at this

This

This simple understanding is the object that invokes the function.

In order to understand this, first understand the following sentence:

  This is to be confirmed at execution time and cannot be confirmed when defined.

And then I'll explain that in the code.

var a = {    ' a '    function  () {       Console.log (this). Name)          }                      }

Look at this code, who is this point?

It is not right to point to anyone now, this is not confirmed at the time of definition, and can only be confirmed at execution time.

Continue with the above code to determine the direction of this.

A.fn ()  //this= = = aa.fn.call ({name:' B '})  //this= = = Name: ' B '}var fn1 = a.fnfn1 ()  //this= = = Window

The answer has been given in the code. Although FN is defined in the A object, the point of this in FN does not always point to a, who calls Fn,this.

Look at the output.

Window does not have a Name property, so the last behavior is empty.

What kind of usage scenario does this have?

Mainly by the following 4 points

    1. Executes as a constructor function
    2. Execute As Object property
    3. Execute as normal function
    4. Call Apply Bind
//execute as a constructor function
function(name) { This. Name =name}varf =NewFoo (' Zhangsan ')//As Object Propertiesvarobj ={name:APrintname:function() {Console.log ( This. Name)}} Obj.printname ()//as a normal objectfunctionfn () {Console.log ( This)//this at this point points to the window}FN ()

The first three kinds of code through the look on the understanding, do not say more, then say the call apply and bind

These three functions are to change the direction of this, and the difference between call and apply is the part that passes the parameter, apply the array, or see it in code.

function fn1 (name,age) {    console.log (name,age)    Console.log (this)}//  The different fn1.call of call and apply usage ({x:100}, ' Zhangsan ', +) fn1.apply ({x:100},[' Zhangsan ', 21])//parameters are placed in the array

The first parameter of call and apply is the point of this, followed by the constructor's arguments.

Output results

As you can see, the output is the same in both ways.

And then the bind,bind is not the same as the previous two, bind is not called when the function executes, but when the function is declared.

Look at the code

var function (name,age) {    console.log (name,age)    Console.log (this)}.bind ({y: $)      bind this to the fn2 (' Lisi ', 22) When the function is declared

Results

It's clear at first glance, not much explained, but one thing to note

Only function expressions can use BIND, and function declarations are not available.

Come up with a wrong demo

function Fn3 (name,age) {    console.log (name,age)    Console.log (this     )}.bind ({z:+})    // Error demo // Error demo fn3 (' Lisi ', 23)

An error.

Scope chain

The first thing to know is that JavaScript is not a block-level scope

if (true) {    var name = "Zhangsan"}console.log (name)

Normal printing, no error.

Second, you also need to know the global scope and function scope

var a =function  fn () {    var a =    console.log (' FN ', a)  // Here's A is the }console.log (' global ', a)  ///  Here's A isthe FN ()

Variables declared in a function are not affected by variables outside, see results

After all this has been learned, let's look at the scope chain.

I don't know how to say the concept, just see it in the code.

var a = 100function fn () {var b = 200console.log (a)  //a is a free variable console.log (b)}FN ()

In FN There is no a variable, when the current scope is not defined by the variable is a free variable, the current scope is not, will go to his superior scope to find, this is the scope chain.

It is also important to note that when a scope chain is defined at all, not at execution time, the scope chain within the function does not become, no matter what scope the function is being downgraded, and then a piece of code

var x =function  F1 () {    var y =      F2 () {         var z =        console.log  (x)// free variable        console.log (y)  // free variable         console.log (z)    }    F2 ()}f1 ()

We look at the x variable, which is a free variable, when the JS engine executes to Console.log (x), it looks for x in the F2, finds it in the parent scope of the current scope without finding it, and finds it on top of it until the global scope is found.

Because the scope chain has been defined, no matter where the function on the chain is called, the scope chain is not changed.

Do you already know how the scope chain works through these two simple codes? Next, introduce closures

Closed Package

For a variety of reasons, we sometimes need to get local variables within the function. However, as already mentioned, under normal circumstances, this can not be done, only through the workaround to achieve.

That is, in the inside of the function, define a function, and then return the function.

function F1 () {    var a = +    // returns a function (function as return value) return functions      () {        console.log (a)    }}//F1 get a function var f1 = F1 ()  var a =F1 ()

Print out

In this case, the closure is implemented, which simply means that the closure is a function that reads the variables inside other functions.

Here's why the print is 100.

See this sentence var F1 = F1 (); F1 The result of this function is to return a function, so it is equivalent to the function within the F1 is paid to the F1 variable, similar to this

var function () {  console.log (a)    //A is a free variable}

Here A is a free variable, so according to the principle of the scope chain, we should go to the first level scope to find. As previously said, the scope chain is defined at the time of definition, and does not have to do with execution, then go to look for, this function definition is defined in F1, so will find a in the F1 variable, so here will print 100.

In this way, we read the variables defined inside the F1 function in the global context, which is the closure.

There are two types of closures that are mainly used in the following scenarios
    • function as return value
    • function as a parameter to pass

In the above example we have implemented the application of the function as the return value of the closure, and then another example is passed as a parameter

function F1 () {    var a =    returnfunction  () {        console.log (a)    }}  var f1 = F1 ()function  F2 (FN) {    var a =     fn ()}f2 (F1)

or the output 100

The example is relatively simple, but can explain the problem, in the closure of the actual application, often to be very complex, but mastered the principle of closure, it is not difficult to achieve.

Examples

To test your understanding of this part of the content.

Create 10 <a> tags and output the corresponding serial number when clicked

The most direct idea of seeing this problem is maybe I am.

Error code Demo
var i,a for (i = 0; i < ten; i++) { = document.createelement (' A ') = i + ' <br/> ' a.addeventlistener (' click ',function(e) { e.preventdefault () Console.log (i) }) Document.body.appendChild (a)}

But that's not right.

As you can see, I'm messing with the label on the left, and the result is 10. Why?

Because the example code is executed synchronously, at the moment the page is loaded, the for loop has been executed, and when I go to the label, I has a value of 10, so no matter how many labels I order, the print will be 10.

How do you solve it?

The solution

 for (var i = 0; i < i++) {    (function(i) {        = document.createelement (' a ') )        = i + ' <br/> '        a.addeventlistener (' click ',function(e) {            E.preventdefault ()            console.log (i)}        )        Document.body.appendChild (a)    }) (i)}

Feature implementation.

I will not explain this problem, if you have mastered the content of this article, this example is very easy to understand.

If you understand the scope chain and closures, it is recommended to continue learning

JavaScript prototype chain

JavaScript classes and inheritance

Finally, if you feel that this article is helpful to you, order a praise ^_^

JavaScript scopes and closures

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.