JavaScript
Scope
Introduce el scope global, de módulo, función y bloque, y explica cómo let, const y var determinan dónde puede utilizarse cada nombre.
- Última actualización
- Actualizada
- Nivel
- Fundamentos
- Fundamentos de programación
JavaScript
Introduce el scope global, de módulo, función y bloque, y explica cómo let, const y var determinan dónde puede utilizarse cada nombre.
El scope es la región del programa donde un nombre puede encontrarse y utilizarse.
function greet() {
const message = "Hello";
console.log(message);
}
greet();
console.log(message); // ReferenceErrorCuando declaras una variable, función, clase o parámetro, JavaScript crea un binding: una asociación entre un nombre y un valor.
const userName = "Nicolás";userName es el nombre."Nicolás" es el valor actual.Dos variables pueden tener el mismo nombre si pertenecen a scopes diferentes.
const status = "global";
function showStatus() {
const status = "local";
console.log(status);
}
showStatus(); // "local"
console.log(status); // "global"Este comportamiento se profundiza en Shadowing.
Un nombre declarado fuera de funciones y bloques pertenece al nivel superior del archivo o script.
const applicationName = "DomiSys";
function printApplicationName() {
console.log(applicationName);
}La función puede leer applicationName porque su scope está contenido dentro del nivel donde fue declarada.
Las variables globales son accesibles desde muchos lugares, pero también aumentan el acoplamiento: cualquier parte del programa puede depender de ellas o modificarlas.
let currentUser = null;
function signIn(user) {
currentUser = user;
}Cuando sea posible, conviene mantener los datos cerca del código que los utiliza y exponer solo lo necesario.
En un script clásico del navegador:
var legacyValue = 10;
let modernValue = 20;legacyValue puede convertirse en una propiedad de window, mientras que modernValue no.
window.legacyValue; // 10
window.modernValue; // undefinedEn módulos, el nivel superior tiene scope de módulo y no crea propiedades globales de esa forma.
Cada módulo tiene su propio espacio de nombres.
// config.js
const apiUrl = "https://api.example.com";
export function getApiUrl() {
return apiUrl;
}apiUrl no puede utilizarse directamente desde otro archivo a menos que se exporte.
// app.js
import { getApiUrl } from "./config.js";
console.log(getApiUrl());Los módulos ayudan a evitar contaminación global y hacen explícitas las dependencias entre archivos. Además, se ejecutan en modo estricto de forma automática.
Cada llamada a una función crea un entorno para sus parámetros y variables locales.
function calculateTotal(price, quantity) {
const subtotal = price * quantity;
return subtotal;
}
calculateTotal(20, 3);Dentro de la función existen:
price y quantity.subtotal.Fuera de la función, esos bindings locales no están disponibles.
console.log(subtotal); // ReferenceErrorUna nueva llamada crea un conjunto nuevo de valores locales.
calculateTotal(20, 3);
calculateTotal(50, 2);Las dos llamadas no comparten sus parámetros ni su variable subtotal.
Un bloque es una sección delimitada por llaves.
{
const message = "Inside the block";
console.log(message);
}
console.log(message); // ReferenceErrorlet, const y class respetan scope de bloque.
if (isAuthenticated) {
const dashboardUrl = "/dashboard";
navigate(dashboardUrl);
}
console.log(dashboardUrl); // ReferenceErrorTambién ocurre en bucles:
for (let index = 0; index < 3; index++) {
console.log(index);
}
console.log(index); // ReferenceErrorif (true) {
var legacyValue = 10;
}
console.log(legacyValue); // 10var tiene scope de función, no de bloque.
function example() {
if (true) {
var value = 10;
}
console.log(value); // 10
}
example();
console.log(value); // ReferenceErrorEsta diferencia es una de las razones por las que el código moderno prefiere const y let.
El parámetro de un catch solo existe dentro de ese bloque.
try {
riskyOperation();
} catch (error) {
console.error(error.message);
}
console.log(error); // ReferenceErrorLas propiedades de un objeto no son variables del scope.
const user = {
name: "Nicolás",
};
console.log(user.name);
console.log(name); // ReferenceErrorname es una propiedad que debe buscarse a través de user; no es un binding independiente.
El scope responde dónde puede utilizarse un nombre.
El tiempo de vida responde durante cuánto tiempo siguen existiendo los datos necesarios.
Una función interna puede conservar acceso al entorno exterior mediante un closure.
function createCounter() {
let count = 0;
return function increment() {
count++;
return count;
};
}
const counter = createCounter();count no puede accederse desde fuera, pero continúa disponible para increment. Los closures se estudiarán después del bloque de funciones.
Un binding con un scope reducido es más fácil de comprender porque existen menos lugares que pueden utilizarlo.
function calculateOrderTotal(items) {
let total = 0;
for (const item of items) {
const lineTotal = item.price * item.quantity;
total += lineTotal;
}
return total;
}lineTotal solo existe dentro de la iteración donde se necesita.
var siempre es global.var y filtrar accidentalmente nombres fuera de un if o bucle.let, const y class respetan scope de bloque.var tiene scope de función.¿Qué imprime este código?
const value = "outside";
function example() {
if (true) {
const value = "inside";
console.log(value);
}
console.log(value);
}
example();
console.log(value);inside
outside
outsideEl value del bloque solo existe dentro del if. Los otros dos accesos encuentran el binding exterior.
Scope léxico y cadena de scopes explica cómo decide JavaScript qué binding utilizar cuando un nombre no existe en el entorno actual.