Pasar NULL como parámetro en ES6 no usa el parámetro predeterminado cuando se proporciona uno

7 minutos de lectura

avatar de usuario de alacy
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!

  • 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és a[0] rendirá el undefined valor a pesar de que 0 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ónde x solo arrojaría/podría arrojar un ReferenceError) no tiene nada que ver con el hecho de que undefined 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

avatar de usuario de rsp
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:

  1. paso undefined es no es el mísmo como no pasar un argumento en absoluto
  2. algunas veces null puede ser un valor predeterminado en lugar de undefined

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 undefinedpor 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 en undefined. Si undefined 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ícitamente undefinedpero 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ícitamente undefinedp.ej doSomething(undefined)ver codepen.io/morewry/pen/KaEVmN?editors=0010.

    – más irónico

    15 de febrero de 2017 a las 2:50

avatar de usuario de taxicala
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

¿Ha sido útil esta solución?