alacia
¿Hay alguna razón conocida por la que pasar null
como parámetro en ES6 no usa el parámetro predeterminado cuando se proporciona uno?
function sayHello(name = "World") {
console.log("Hello, " + name + "!");
}
sayHello("Jim"); // Hello, Jim!
sayHello(undefined); // Hello, World!
sayHello(null); // Hello, null!
rsp
Esto no es tan obvio
He leído algunos comentarios de por qué undefined
es completamente diferente a null
y por eso explica el comportamiento actual de los parámetros predeterminados.
Se podría argumentar que pasar explícitamente indefinido no debe activar la sustitución del valor predeterminado porque cuando tengo una función:
const f = (x = 'default') => console.log(x);
me gustaria que se imprima "default"
cuando lo ejecuto como:
f();
pero me gustaria que se imprimiera "undefined"
cuando lo ejecuto explícitamente como:
f(undefined);
porque de lo contrario, ¿por qué usaría f(undefined)
¿en primer lugar? Claramente, mi intención aquí es proporcionar algún argumento en lugar de omitirlo.
Ejemplos de lo contrario
Ahora, considere esta función:
const g = (...a) => console.log(JSON.stringify(a));
Cuando lo uso como:
g();
Yo obtengo: []
Pero cuando lo uso como:
g(undefined);
Yo obtengo: [null]
lo que demuestra claramente que:
- paso
undefined
es no es el mísmo como no pasar un argumento en absoluto - algunas veces
null
puede ser un valor predeterminado en lugar deundefined
decisión TC39
Se pueden ver algunos antecedentes sobre el comportamiento actual de los parámetros predeterminados en las Notas de la reunión del 24 de julio de 2012 de TC39:
Por cierto, muestra que pasar explícitamente undefined
originalmente No desencadenar el valor predeterminado en el primer borrador y hubo una discusión sobre si debería hacerlo o no. Entonces, como puede ver, el comportamiento actual no era tan obvio para los miembros de TC39 como ahora parece ser para las personas que comentan aquí.
Otros idiomas
Dicho esto, la decisión de qué debe y qué no debe desencadenar la sustitución del valor predeterminado es completamente arbitraria al final del día. Incluso teniendo un separado undefined
y null
puede parecer bastante extraño si lo piensas. Algunos lenguajes solo tienen undefined
(me gusta undef
en Perl), algunos solo tienen null
(como Java), algunos lenguajes usan equivalentes de false
o una lista o matriz vacía para eso (como Esquema donde puede tener una lista vacía o #f
(falso) pero no hay equivalente de null
eso sería distinto tanto de una lista vacía como de un valor falso) y algunos idiomas ni siquiera tienen equivalentes de null
, false
o undefined
(como C que usa números enteros en lugar de true
y false
y un puntero NULL que en realidad es un puntero normal que apunta a la dirección 0, lo que hace que esa dirección sea inaccesible incluso cuando se asigna mediante cualquier código que pruebe los punteros nulos).
Lo que puedes hacer
Ahora, puedo entender su necesidad de sustituir los valores predeterminados por null
. Desafortunadamente, este no es un comportamiento predeterminado, pero puede crear una función simple para ayudarlo:
const N = f => (...a) => f(...a.map(v => (v === null ? undefined : v)));
Ahora, cada vez que desee sustituir los valores predeterminados null
valores puede usarlo así. Por ejemplo, si tiene esta función de uno de los ejemplos anteriores:
const f = (x = 'default') => console.log(x);
imprimirá "default"
por f()
y f(undefined)
pero no para f(null)
. Pero cuando usas el N
función definida anteriormente para definir el f
funcionar así:
const f = N((x = 'default') => console.log(x));
ahora f()
y f(undefined)
pero también f(null)
huellas dactilares "default"
.
Si desea un comportamiento algo diferente, por ejemplo, sustituir los valores predeterminados por cadenas vacías, útil para las variables de entorno que a veces se pueden establecer en cadenas vacías en lugar de no existir, puede usar:
const N = f => (...a) => f(...a.map(v => (v === '' ? undefined : v)));
Si desea que se sustituyan todos los valores falsos, puede usarlo así:
const N = f => (...a) => f(...a.map(v => (v || undefined)));
Si desea que se sustituyan los objetos vacíos, puede usar:
const N = f => (...a) => f(...a.map(v => (Object.keys(v).length ? v : undefined)));
y así…
Conclusión
El punto es que es tu código y sabes cuál debería ser la API de tus funciones y cómo deberían funcionar los valores predeterminados. Afortunadamente, JavaScript es lo suficientemente poderoso como para permitirle lograr fácilmente lo que necesita (incluso si ese no es el comportamiento predeterminado de los valores predeterminados, por así decirlo) con algunas funciones mágicas de orden superior.
-
impresionante respuesta! Muy profundo y bien explicado.
– alacy
21 de abril de 2017 a las 13:55
-
Ahora, pasar explícitamente undefined debería además activar la sustitución del valor predeterminado
– ArunCM
11 de julio de 2020 a las 17:06
-
@rsp, gracias por su respuesta, después de cuatro años llegué exactamente a la razón de mi problema.
– AmerllicA
9 oct 2021 a las 4:20
Así es como se definen los parámetros predeterminados en la especificación. Ver MDN: (énfasis mío)
Los parámetros de función predeterminados permiten que los parámetros formales se inicialicen con valores predeterminados si sin valor o indefinido esta pasado.
null
Es ninguno sin valorni undefined
por lo que no activa la inicialización predeterminada.
-
Y la razón por la cual
undefined
se trata de forma especial porque los parámetros “vacíos” se establecen enundefined
. Siundefined
no era equivalente a “sin valor”, esto sería más molesto de implementar:function foo(bar) { return functionWithDefaults(bar); }; foo();
. El inconveniente es que no es posible pasar explícitamenteundefined
pero quien hace eso de todos modos 😛– Félix Kling
22/09/2015 a las 23:44
-
¿Alguien sabe por qué decidieron que este era el camino correcto a seguir? Me parece que nulo debería desencadenar el uso de un valor predeterminado.
– Pensando en bits
08/08/2016 a las 19:39
-
Es posible pasar explícitamente
undefined
pasando explícitamenteundefined
p.ejdoSomething(undefined)
ver codepen.io/morewry/pen/KaEVmN?editors=0010.– más irónico
15 de febrero de 2017 a las 2:50
taxicala
null
es un valor que no desencadenará el uso del valor predeterminado, los valores predeterminados se usarán cuando el argumento sea undefined
.
código de versión ramdajs
// import ramda
// infra code
const isEmptyOrNil = (value) => isEmpty(value) || isNil(value)
const nullChange = (defaultValue) => (value) => isEmptyOrNil(value)? defaultValue: value
// single null
const _somef = (value) => value
const somefWithDefault = (defaultValue) => pipe(nullChange(defaultValue), _somef)
const somef = somefWithDefault('myValue')
somef(null)
// many args
const _somef2 = (value, value2, value3) => value + value2 + value3
const nullChangeMyValue = nullChange('myValue')
const somef2 = useWith(_somef2, [nullChangeMyValue, nullChangeMyValue, nullChangeMyValue])
somef2(null, undefined, 1234)
// many args2 version2
const nullChangeWith = (defaultValue) => nullChange(defaultValue)
const arrayNullChangeWith = (defaultValue) => (array) => array.map(nullChangeWith(defaultValue))
const arg2Array = (...args) => args
const funcApplyDefaultValue = (defaultValue) => (func) => pipe(
arg2Array, arrayNullChangeWith(defaultValue), apply(func)
)
const v2somef2 = funcApplyDefaultValue(8)(_somef2)
v2somef2(1,2,null)
gits: https://gist.github.com/otwm/3a6358e53ca794cc2e57ade4af91d3bb
porque nulo es un valor válido?
– toskv
22/09/2015 a las 19:14
no, no lo es 🙂 puedes leer sobre la diferencia entre indefinido y nulo aquí stackoverflow.com/questions/5076944/…
– toskv
22/09/2015 a las 19:17
@toskv Si
undefined
estaba no un valor entonces podría no ser asignado, sin embargo, puede ser. Esta es la prueba más simple para determinar si algo es un valor. Y simplemente, esa respuesta es incorrecta para usar en contexto:undefined
se utiliza como un valor por defecto en algunos casos; esto no es hacer indefinido ‘no es un valor’. Considerar:a = new Array(1)
. Despuésa[0]
rendirá elundefined
valor a pesar de que0 in a
Es falso. eso,a[0]
contiene ‘sin valor’ a pesar de que lo hará evaluar al (predeterminado)undefined
valor.– usuario2864740
22/09/2015 a las 19:17
@toskv He explicado anteriormente por qué eso es incorrecto. Hablando de ‘si no se definió la variable’ (en el caso de
typeof x === 'undefined'
dóndex
solo arrojaría/podría arrojar un ReferenceError) no tiene nada que ver con el hecho de queundefined
es un valor. En particular, ‘indefinido’ en JavaScript no no estrictamente significa ‘no ha sido definido/declarado’.– usuario2864740
22/09/2015 a las 19:21
Creo que me expresé mal antes. No es que la variable no esté definida, en ese caso la variable apunta a un valor que aún no ha sido definido. Mientras que var x = null significa que x tiene el valor definido de nulo. Puede pensar en undefined como no inicializado, mientras que null se inicializa sin valor. Es confuso, lo sé. @Félix Kling
– toskv
23 de septiembre de 2015 a las 5:44