Shadowing en JavaScript: variables que ocultan bindings | Nicolás Garzón
El shadowing ocurre cuando un scope interior declara un binding con el mismo nombre que uno exterior. Mientras el binding interior esté visible, oculta al exterior.
JavaScript
Copiar const status = "global" ;
function showStatus ( ) {
const status = "local" ;
console. log ( status) ;
}
showStatus ( ) ;
console. log ( status) ; La resolución comienza en el scope actual.
JavaScript
Copiar const role = "viewer" ;
function openPanel ( ) {
const role = "admin" ;
console. log ( role) ;
} Dentro de openPanel, JavaScript encuentra primero el binding local role y deja de buscar hacia fuera.
JavaScript
Copiar let count = 0 ;
function increment ( ) {
count++ ;
} Aquí la función encuentra el binding exterior y lo reasigna.
JavaScript
Copiar let count = 0 ;
function increment ( ) {
let count = 0 ;
count++ ;
} La segunda función crea un binding local nuevo. El count exterior permanece en 0.
JavaScript
Copiar const message = "outside" ;
{
const message = "inside" ;
console. log ( message) ;
}
console. log ( message) ; Texto
Copiar inside
outsideJavaScript
Copiar const currency = "COP" ;
function formatPrice ( value, currency ) {
return ` ${ value} ${ currency} ` ;
}
formatPrice ( 50000 , "USD" ) ; El parámetro currency oculta al binding exterior dentro de la función.
JavaScript
Copiar let total = 0 ;
for ( const order of orders) {
const total = order. items. reduce (
( sum, item ) => sum + item. price,
0 ,
) ;
}
console. log ( total) ; El total del bloque es distinto al exterior. Si la intención era acumular el resultado general, el shadowing produce un error lógico.
JavaScript
Copiar let total = 0 ;
for ( const order of orders) {
const orderTotal = order. items. reduce (
( sum, item ) => sum + item. price,
0 ,
) ;
total += orderTotal;
} JavaScript
Copiar const price = 100 ;
{
console. log ( price) ;
const price = 200 ;
} El bloque ya contiene una declaración local llamada price. Ese binding oculta al exterior desde el comienzo del bloque, pero permanece sin inicializar hasta su declaración.
Esto es una redeclaración inválida en el mismo scope:
JavaScript
Copiar const user = "Nicolás" ;
const user = "Nico" ; Esto es shadowing válido en scopes diferentes:
JavaScript
Copiar const user = "Nicolás" ;
function example ( ) {
const user = "Nico" ;
} JavaScript
Copiar let value = 10 ;
{
var value = 20 ;
} var pertenece al scope de función o script, por lo que chocaría con el let exterior del mismo entorno relevante.
La dirección contraria sí puede crear un binding de bloque:
JavaScript
Copiar var value = 10 ;
{
let value = 20 ;
console. log ( value) ;
}
console. log ( value) ; Un nombre local puede ocultar constructores, objetos o funciones globales.
JavaScript
Copiar function parseInput ( String ) {
return String ( value) ;
} Aquí el parámetro String oculta al constructor global String.
Otros nombres que conviene no ocultar sin una razón clara incluyen:
Array
Object
Promise
Date
JSON
Math
console
undefined
JavaScript
Copiar const user = { id : "user-1" } ;
users. forEach ( ( user ) => {
console. log ( user. id) ;
} ) ; El parámetro del callback oculta al user exterior. Una opción más clara puede ser:
JavaScript
Copiar users. forEach ( ( currentUser ) => {
console. log ( currentUser. id) ;
} ) ; JavaScript
Copiar let total = 0 ;
for ( const order of orders) {
const orderTotal = calculateOrderTotal ( order) ;
total += orderTotal;
} JavaScript
Copiar const users = await getUsers ( ) ;
function transformUsers ( sourceUsers ) {
} Reglas como no-shadow pueden detectar nombres interiores que ocultan bindings exteriores.
Confundir shadowing con reasignación.
Declarar un acumulador local con el mismo nombre del acumulador exterior.
Ocultar sin querer un parámetro de configuración.
Reutilizar nombres genéricos como data, result o value en muchos niveles.
Ocultar constructores y APIs globales.
Esperar que el binding exterior sea visible antes de una declaración local dentro del mismo bloque.
Llamar redeclaración a algo que ocurre en scopes diferentes.
El binding más cercano oculta a los bindings exteriores con el mismo nombre.
El shadowing crea un binding nuevo; no modifica automáticamente al exterior.
La redeclaración ocurre en el mismo scope y puede ser inválida.
Un binding local en TDZ puede ocultar al exterior antes de inicializarse.
var interactúa de forma distinta con los scopes de bloque.
Ocultar nombres globales puede romper código de manera poco evidente.
El shadowing es válido, pero debe mejorar la claridad en lugar de reducirla.
¿Qué imprime este código?
JavaScript
Copiar let value = 1 ;
function example ( value ) {
value += 1 ;
console. log ( value) ;
}
example ( 10 ) ;
console. log ( value) ; Respuesta Texto
Copiar 11
1El parámetro value oculta al binding exterior. La reasignación ocurre únicamente sobre el parámetro local.
Hoisting explica en qué estado existen las declaraciones antes de que la ejecución alcance la línea donde fueron escritas.