Scope and context usage in JavaScript brief overview _ Basics

Source: Internet
Author: User
Tags closure inheritance variable scope
The scope and context (contexts) in JavaScript are unique to the language, thanks in part to the flexibility they bring. Each function has a different context and scope of variables. These concepts are backed by some powerful design patterns in JavaScript. However, this also brings a lot of confusion to the developers. The following is a complete revelation of the context and scope in JavaScript and how various design patterns use them.

Context vs Scope

The first problem to be clarified is that context and scope are different concepts. Over the years I've noticed that many developers confuse the two terms, incorrectly describing one as another. In all fairness, these terms have become very confusing.

Each function call has a scope and context associated with it. Fundamentally, scopes are based on functions (function-based) and contexts are object-based (object-based). In other words, the scope is related to the access of the variable every time the function is called, and each invocation is independent. The context is always the value of the keyword this, and is a reference to the object that invokes the current executable code.

Variable Scope

Variables can be defined in local or global scope, which results in the access of Run-time variables from different scopes. Global variables need to be declared outside of the function body and exist throughout the run, and can be accessed and modified in any scope. Local variables are defined in the function body only, and each function call has a different scope. This topic is an assignment, evaluation, and manipulation of values only in calls that cannot access values outside the scope.

Currently, JavaScript does not support block-level scopes, block-level scopes are defined as variables in statement blocks such as if statements, switch statements, and circular statements, which means that variables cannot be accessed outside the statement block. Any variable currently defined in a statement block can be accessed outside of a statement block. However, this situation will soon change and the LET keyword has been formally added to the ES6 specification. Use it instead of the VAR keyword to declare a local variable as a block-level scope.

the "This" context

The context usually depends on how a function is invoked. When a function is invoked as a method of an object, this is set to the object that invokes the method:

Copy Code code as follows:

var object = {
Foo:function () {
Alert (This = = object);
}
};

Object.foo (); True

The same principle applies when a function is invoked to create an instance of an object through the operator of new. When called in this manner, the value of this is set to the newly created instance:
Copy Code code as follows:

function foo () {
alert (this);
}

Foo ()//window
New Foo ()//foo

When an unbound function is invoked, this will be set to the global context or Window object (if in the browser) by default. However, if the function is executed in strict mode ("use strict"), the value of this will be set to undefined by default.
Execution context and scope chain

JavaScript is a single-threaded language, which means that only one thing can be done in the browser at the same time. When the JavaScript interpreter initially executes the code, it defaults to the global context first. Each call to a function creates a new execution context.

This is often confusing, and the term "execution context" here is meant to be a scope, not the context of the previous discussion. Execution This is the name of the slot cake, however, the term ECMAScript defined by the specification, and helplessly complied with it.

Each time a new execution context is created, it is added to the top of the scope chain and is also an execution or call stack. The browser always runs at the current execution context at the top of the scope chain. Once completed, it (the current execution context) will be removed from the top of the stack and the control will be returned to the previous execution context. For example:
Copy Code code as follows:

function A () {
Second ();
function second () {
Third ();
function third () {
Fourth ();
function Fourth () {
Do something
}
}
}
}
A ();

Running the preceding code will cause nested functions to fall from the top until the fourth function, at which point the scope chain goes from top to bottom: Fourth, third, second, first, global. The fourth function is able to access global variables and any variables defined in the First,second and third functions just as you would access your own variables. Once the fourth function completes, the fourth Halo happy context is removed from the top of the scope chain and execution is returned to the Thrid function. This process continues until all code has completed execution.

Variable naming conflicts between different execution contexts are resolved by climbing the scope chain, from local to global. This means that local variables with the same name have a higher priority in the scope chain.

Simply put, every time you try to access a variable in the execution context of a function, the lookup process always starts with its own variable object. If the variable you are looking for is not found in your own variable object, continue searching the scope chain. It will climb the scope chain to examine the variable object of each execution context to find the value that matches the variable name.

Closed Bag

When a nested function is accessed outside the definition (scope), it can be executed after the external function returns, at which point a closure is formed. It (closures) maintains (in internal functions) access to local variables, arguments, and function declarations in external functions. Encapsulation allows us to hide and protect the execution context from an external scope and expose the public interface for further operation through the interface. A simple example looks like the following:
Copy Code code as follows:

function foo () {
var local = ' private variable ';
return function bar () {
return to local;
}
}

var getlocalvariable = foo ();
GetLocalVariable ()//private variable

One of the most popular types of closures is the well-known modular model. It allows you to simulate public, private, and privileged members:
Copy Code code as follows:

var Module = (function () {
var privateproperty = ' Foo ';

function Privatemethod (args) {
Do something
}

return {

Publicproperty: "",

Publicmethod:function (args) {
Do something
},

Privilegedmethod:function (args) {
Privatemethod (args);
}
}
})();

The module is actually somewhat similar to a single example, adding a pair of parentheses at the end and executing immediately when the interpreter is explained (immediately executing the function). The only available member outside of the closure execution level is the method and property (such as Module.publicmethod) that are common in the return object. However, all private properties and methods will exist throughout the life cycle of the program, and because (closures) enable the execution context to be protected, the interaction with the variables is passed through a common method.

Another type of closure is called an immediate invocation of a function expression (immediately-invoked function expression Iife), which is nothing more than a self invocation anonymous function in the window context (self-invoked Anonymous function).
Copy Code code as follows:

function (window) {

var a = ' Foo ', B = ' bar ';

function Private () {
Do something
}

Window. Module = {

Public:function () {
Do something
}
};

}) (this);

This expression is useful for protecting the global namespace, and all variables declared in the function body are local variables and persist throughout the running environment through closures. This way of encapsulating the source code is very popular with both the program and the framework, often exposing a single global interface interacting with the outside world.

Call and Apply

These two simple methods, built into all functions, allow functions to be executed in a custom context. The call function requires a parameter list and the Apply function allows you to pass arguments to an array:
Copy Code code as follows:

function User (I, last, age) {
Do something
}
User.call (window, ' John ', ' Doe ', 30);
user.apply (window, [' John ', ' Doe ', 30]);

The result is the same, the user function is invoked on the window context, and the same three parameters are provided.

ECMAScript 5 (ES5) introduces the Function.prototype.bind method to control the context, which returns a new function (the context) that is permanently bound to the first parameter of the Bind method, regardless of how the function is invoked. It modifies the context of the function by closures, and the following is a scenario for browsers that are not supported:
Copy Code code as follows:

if (! (' Bind ' in Function.prototype) ') {
Function.prototype.bind = function () {
var fn = This, context = arguments[0], args = Array.prototype.slice.call (arguments, 1);
return function () {
Return fn.apply (context, args);
}
}
}

It is commonly used in context loss: object-oriented and event handling. This is necessary because the AddEventListener method of the node always retains the context of the function execution for the event-handling bound node, which is important. However, if you use advanced object-oriented techniques and need to maintain the context of the callback function as an instance of the method, you must manually adjust the contexts. This is the convenience that bind brings:
Copy Code code as follows:

function MyClass () {
This.element = document.createelement (' div ');
This.element.addEventListener (' Click ', This.onClick.bind (this), false);
}

MyClass.prototype.onClick = function (e) {
Do something
};

When reviewing the source code of the BIND function, you may notice a relatively simple line of code that invokes a method of array:
Copy Code code as follows:

Array.prototype.slice.call (arguments, 1);

Interestingly, it is important to note that the arguments object is not actually an array, but it is often described as an array of classes (Array-like) objects, very nodelist (document.getElementsByTagName () The result of the method return. They contain lenght attributes, values can be indexed, but they are still not arrays because they do not support native array methods such as slice and push. However, because they have arrays of similar behaviors, the array method can be invoked and hijacked. If you want to do this, execute the array method in the context of the class array, referring to the example above.

This technique of invoking other object methods is also applied to object-oriented, while imitating classic inheritance (class inheritance) in javascript:
Copy Code code as follows:

MyClass.prototype.init = function () {
Call the superclass Init method in the "MyClass" instance
MySuperClass.prototype.init.apply (this, arguments);
}

By invoking the superclass (Mysuperclass) method in instances of subclasses (MyClass), we can reproduce this powerful design pattern.

Conclusions

It is important to understand these concepts before you begin to learn advanced design patterns, because scopes and contexts play an important and fundamental role in modern JavaScript. Whether we talk about closures, object-oriented, and inheritance or various native implementations, contexts and scopes play an important role. If your goal is to master the JavaScript language and get a deeper understanding of its composition, the scope and context should be your starting point.

Translator Supplement

The BIND function implemented by the author is not complete, and the following code fixes the problem by calling the function returned by bind without passing the argument:

Copy Code code as follows:

if (! Bind ' in Function.prototype)} {
Function.prototype.bind = Function () {
var fn = This, context = arguments[0], AR GS = Array.prototype.slice.call (arguments, 1);
Return function () {
return fn.apply (context, args.concat (arguments));//fixed
}
}
}
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.