search
HomeWeb Front-endJS TutorialA brief overview of scope and context usage in JavaScript_Basics

Scope and context in JavaScript are unique to the language, thanks in part to the flexibility they bring. Each function has different variable context and scope. These concepts underlie some powerful design patterns in JavaScript. However, this also brings great confusion to developers. The following comprehensively reveals the differences between context and scope in JavaScript, and how various design patterns use them.

Context vs Scope

The first thing that needs to be clarified is that context and scope are different concepts. Over the years I've noticed that many developers often confuse these two terms, incorrectly describing one as the other. To be fair, these terms have become very confusing.

Each function call has a scope and context associated with it. Basically, scope is function-based and context is object-based. In other words, scope is related to the access of variables on each function call, and each call is independent. The context is always the value of the keyword this, which is a reference to the object that calls the current executable code.

Variable Scope

Variables can be defined in local or global scopes, which results in runtime variable access from different scopes. Global variables need to be declared outside the function body, exist throughout the running process, and can be accessed and modified in any scope. Local variables are only defined within the function body and have a different scope for each function call. This topic is assignment, evaluation and operation of values ​​only within the call, and values ​​outside the scope cannot be accessed.

Currently JavaScript does not support block-level scope. Block-level scope refers to defining variables in statement blocks such as if statements, switch statements, loop statements, etc. This means that variables cannot be accessed outside the statement block. Currently any variables defined within a statement block can be accessed outside the statement block. However, this will soon change, as the let keyword has been officially added to the ES6 specification. Use it instead of the var keyword to declare local variables as block-level scope.

"this" context

Context usually depends on how a function is called. When a function is called as a method of an object, this is set to the object on which the method is called:

Copy code The code is as follows :

var object = {
foo: function(){
alert(this === object);
}
};

object.foo(); // true

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

function foo(){
alert(this);
}

foo() // window
new foo() // foo

When calling an unbound function, this will be set to the global context or window object (if in a 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 at the same time in the browser. When the JavaScript interpreter initially executes code, it first defaults to the global context. Each time a function is called a new execution context is created.

Confusion often occurs here. The term "execution context" here means scope, not the context discussed above. This is poor naming, but the term is defined by the ECMAScript specification and has no choice but to abide by it.

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

function first(){
second( );
function second(){
third();
function third(){
fourth();
function fourth(){
// do something
}
}
}
}
first();

Running the previous code will cause the nested functions to be executed from top to bottom until the fourth function. At this time, the scope chain from top to bottom is: fourth, third, second, first, global. The fourth function can access global variables and any variables defined in the first, second, and third functions just like its own variables. Once the fourth function completes execution, the fourth context will be removed from the top of the scope chain and execution will return 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 higher priority in the scope chain.

Simply put, every time you try to access a variable in the function execution context, the lookup process always starts from 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 and examine each execution context variable object to find a value that matches the variable name.

Closure

When a nested function is accessed outside its definition (scope) so that it can be executed after the outer function returns, then A closure is formed. It (the closure) maintains (in the inner function) access to local variables, arguments and function declarations in the outer function. Encapsulation allows us to hide and protect the execution context from the external scope, while exposing the public interface through which further operations can be performed. A simple example looks like this:
Copy the code The code looks like this:

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

var getLocalVariable = foo();
getLocalVariable() // private variable

One of the most popular closure types is the well-known module pattern. It allows you to mock public, private and privileged members:
Copy the code The code is 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 singleton, adding a pair of brackets at the end when explaining Execute immediately after the processor has finished interpreting it (execute the function immediately). The only available external members of the closure execution context are the public methods and properties in the returned object (such as Module.publicMethod). However, all private properties and methods will exist throughout the life cycle of the program, because the execution context is protected (closures), and interaction with variables is through public methods.

Another type of closure is called an immediately-invoked function expression IIFE, which is nothing more than a self-invoked anonymous function in the window context.
Copy code The code is as follows:

function(window){

var a = 'foo', b = 'bar';

function private(){
// do something
}

window.Module = {

public: function(){
// do something
}
};

})(this);

To protect the global namespace, This expression is very useful. All variables declared within the function body are local variables and persist throughout the entire runtime environment through closures. This way of encapsulating source code is very popular for both programs and frameworks, usually exposing a single global interface to interact with the outside world.

Call and Apply

are two simple methods built into all functions that allow functions to be executed in a custom context. The call function requires a parameter list and the apply function allows you to pass the parameters as an array:
Copy the code The code is as follows:

function user(first, last, age){
// do something
}
user.call(window, 'John', 'Doe', 30);
user.apply (window, ['John', 'Doe', 30]);

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

ECMAScript 5 (ES5) introduced the Function.prototype.bind method to control the context. It returns a new function. This function (the context) is permanently bound to the first parameter of the bind method, regardless of the function. How to be called. It corrects the context of the function through closure. The following is a solution for unsupported browsers:
Copy the code The code is 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 processing. This is necessary because the node's addEventListener method always maintains the context of function execution as the node to which the event handler is bound, which is important. However, if you use advanced object-oriented techniques and need to maintain the callback function's context as an instance of the method, you must manually adjust the context. This is the convenience brought by bind:
Copy code The code is 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 looking back at the source code of the bind function, you may notice that the following line is relatively Simple code, calling a method of Array:
Copy code The code is as follows:

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

Interestingly, it is important to note here that the arguments object is not actually an array, however it is often described as an array-like ) object, which is the result returned by nodelist (document.getElementsByTagName() method). They contain length attributes, and the values ​​can be indexed, but they are still not arrays because they do not support native array methods such as slice and push. However, since they behave similarly to arrays, array methods can be called and hijacked. If you want to execute array methods in an array-like context, follow the example above.

This technique of calling other object methods is also applied to object-oriented, when emulating classic inheritance (class inheritance) in JavaScript:
Copy Code The code is as follows:

MyClass.prototype.init = function(){
// call the superclass init method in the context of the "MyClass" instance
MySuperClass.prototype.init.apply(this, arguments);
}

By calling the method of the superclass (MySuperClass) in the instance of the subclass (MyClass), we can reproduce this powerful design pattern.

Conclusion

It is very important to understand these concepts before you start learning advanced design patterns, since scope and context play an important and fundamental role in modern javascript Role. Whether we talk about closures, object-oriented, and inheritance or various native implementations, context and scope play an important role. If your goal is to master the JavaScript language and gain a deep understanding of its components, scope and context should be your starting point.

Translator’s Supplement

The bind function implemented by the author is incomplete. Parameters cannot be passed when calling the function returned by bind. The following code fixes this problem:

Copy code The code is 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.concat(arguments));//fixed
}
}
}
Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
switch case 内变量的范围switch case 内变量的范围Feb 09, 2024 am 09:00 AM

packagemainimport"fmt"funcmain(){x:=10switchx{case0:y:='a'fmt.Printf("%c\n",y)case1://y='b'//thiscan'tcompile,y:='b'fmt.Printf("%c\n",y)default:y:=

Linux多线程编程锁详解:如何避免竞争和死锁Linux多线程编程锁详解:如何避免竞争和死锁Feb 11, 2024 pm 04:30 PM

在Linux多线程编程中,锁是一种非常重要的机制,可以避免线程间的竞争和死锁。然而,如果不正确使用锁,可能会导致性能下降和不稳定的行为。本文将介绍Linux中的常见锁类型,如何正确使用它们,以及如何避免竞争和死锁等问题。在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为”互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。Linux实现的互斥锁机制包括POSIX互斥锁和内核互斥锁,本文主要讲POSIX互斥锁,即线程间互斥锁。信号量用在多线程

详解Golang函数中的变量作用域详解Golang函数中的变量作用域Jan 18, 2024 am 08:51 AM

Golang函数中的变量作用域详解在Golang中,变量的作用域指的是变量的可访问范围。了解变量的作用域对于代码的可读性和维护性非常重要。在本文中,我们将深入探讨Golang函数中的变量作用域,并提供具体的代码示例。在Golang中,变量的作用域可以分为全局作用域和局部作用域。全局作用域指的是在所有函数外部声明的变量,即在函数之外定义的变量。这些变量可以在整

掌握JavaScript函数的嵌套和作用域掌握JavaScript函数的嵌套和作用域Nov 03, 2023 pm 07:55 PM

掌握JavaScript函数的嵌套和作用域,需要具体代码示例在JavaScript编程中,函数是非常重要的概念。函数的嵌套和作用域能够极大地提高代码的可读性和灵活性。本文将介绍如何正确地使用嵌套函数和作用域,并提供具体的代码示例。函数的嵌套可以理解为在一个函数中定义了另一个函数。这种嵌套的方式能够将代码分成多个小块,使得程序的逻辑更加清晰。同时,嵌套函数还可

Python Lambda表达式:让编程变得更轻松Python Lambda表达式:让编程变得更轻松Feb 19, 2024 pm 09:54 PM

pythonLambda表达式是一个小的匿名函数,它可以将一个表达式存储在变量中并返回它的值。Lambda表达式通常用于执行简单的任务,这些任务可以通过编写一个单独的函数来完成,但Lambda表达式可以使代码更简洁和易读。Lambda表达式的语法如下:lambdaarguments:expressionarguments是Lambda表达式接收的参数列表,expression是Lambda表达式的体,它包含需要执行的代码。例如,以下Lambda表达式将两个数字相加并返回它们的和:lambdax,

JavaScript const关键字的用法及作用JavaScript const关键字的用法及作用Feb 19, 2024 pm 06:30 PM

JavaScript中const的作用和用法JavaScript是一种广泛应用于网页开发的编程语言,其具有灵活性和动态性是其特点之一。在JavaScript中,我们可以使用const关键字来声明一个常量。本文将介绍const关键字的作用和用法,并提供一些具体的代码示例来帮助读者更好地理解。const的作用const(常量)是一种用于声明不可更改的变量的关键字

c语言static的作用和用法是什么c语言static的作用和用法是什么Jan 31, 2024 pm 01:59 PM

c语言static的作用和用法:1、变量作用域;2、生命周期;3、函数内部;4、修饰全局变量;5、修饰函数;6、其他用途;详细介绍:1、变量作用域,当一个变量前有static关键字,那么这个变量的作用域被限制在声明它的文件内,也就是说,这个变量是“文件级作用域”,这对于防止变量的“重复定义”问题很有用;2、生命周期,静态变量在程序开始执行时初始化一次,并在程序结束时销毁等等。

如何解决Python的变量未定义错误?如何解决Python的变量未定义错误?Jun 24, 2023 pm 10:12 PM

Python是一种高级编程语言,它的易用性和流行程度使得它成为了众多程序员的首选语言。与其他语言一样,Python也存在一些常见的错误类型,例如变量未定义错误。当我们在Python中使用一个未定义的变量时,程序就会抛出一个名为“NameError”的异常。这种错误通常出现在以下几种情况下:拼写错误:可能是因为变量名拼写错误导致了变量未定义错误,我们需要仔细检

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Atom editor mac version download

Atom editor mac version download

The most popular open source editor