Si new A() y new B() son ambos idempotentes, ¿no esperaría siempre new A(); new B(); para tener éxito si new B(); new A(); tiene éxito?
Lo siguiente produce un error confuso (confuso porque no estoy tratando de hacer referencia a host , sino que lo proporciono como parámetro a B, que tiene como parámetro de constructor):
#app.js const DEFAULT_HOST = "localhost"; class B { constructor(host = null) { console.log(`HOST: ${host}`); } } class A { constructor() { new B(host = DEFAULT_HOST) } } console.log(new A()); console.log(new B(host=123)); % npm app.js constructor() { new B(host = DEFAULT_HOST) } ^ ReferenceError: host is not defined at new A (/home/sir/app.js:8:32) at Object.<anonymous> (/home/sir/app.js:11:13) at Module._compile (internal/modules/cjs/loader.js:1158:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10) at Module.load (internal/modules/cjs/loader.js:1002:32) at Function.Module._load (internal/modules/cjs/loader.js:901:14) at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12) at internal/main/run_main_module.js:18:47Pero cambia las dos últimas líneas y no hay excepción. ¡¿Eh?!
console.log(new B(host=123)); console.log(new A());Lo siguiente funciona bien, así que debo suponer que tiene algo de magia con las clases:
const DEFAULT_HOST = "localhost"; function b(host = null) { console.log(`HOST: ${host}`); } function a() { b(host = DEFAULT_HOST) } console.log(a()); console.log(b(host=123));Tienes tu notación confundida, por ejemplo. Los parámetros de las funciones JS no tienen nombres: para pasar un valor, simplemente pase el valor, independientemente del nombre que usen las funciones internas. Este:
console.log(new B(host=123));debiera ser
console.log(new B(123)); para que el constructor de B vea el argumento 123 y lo coloque en el identificador de host .
En cuanto a por qué se produce el error: no puede recuperar un valor de un identificador que no existe, pero (en modo descuidado) puede asignar un valor a un identificador que no existe, lo que hace que la propiedad se coloque en el global objeto. Por ejemplo:
// OK bar = '123'; // forbidden console.log(foo);(Siempre declare las variables antes de usarlas y considere usar siempre el modo estricto).
Esto arroja un error en modo estricto:
new B(host = DEFAULT_HOST)porque es equivalente a: ( primero resolviendo la expresión en la lista de argumentos):
const result = (host = DEFAULT_HOST); new B(result);Y los constructores se ejecutan en modo estricto, lo que prohíbe la asignación a identificadores inexistentes:
class B { constructor() { function foo() { console.log(this); } foo(); } } new B();Pero el código fuera de una clase puede no estar en modo estricto , como en su código. En modo descuidado, se permite la asignación a un identificador inexistente (simplemente muy extraño de hacer).
// IN SLOPPY MODE, so the following is permitted (but strange): bar = 'bar'; class B { constructor() { // IN STRICT MODE, so the following is forbidden: foo = 'foo'; } } new B(); Su código con new B(host = DEFAULT_HOST) falla en modo estricto (dentro del constructor) porque el identificador de host no existe y no se lanza en modo descuidado (fuera del constructor).
Cuando llama a una función (un método de clase, un constructor de clase, una función anónima), el javascript se evalúa antes de pasar el valor. JavaScript evalúa la asignación y luego pasa el resultado de la asignación a la función.
'use strict' const DEFAULT_HOST = 'localhost'; let foo; class B { constructor(host) { console.log(`B created with "${host}"`); } } new B(foo = DEFAULT_HOST); En este caso, js intenta asignar DEFAULT_HOST a una variable llamada host . Pero, ¿qué es el anfitrión? host no está definido. Entonces arroja un error.
'use strict'; const DEFAULT_HOST = 'localhost'; class B { constructor(foo) { console.log(`B created with "${foo}"`); } } // Uncaught ReferenceError: foo is not defined new B(foo = DEFAULT_HOST);El valor de parámetro predeterminado se asigna a un parámetro si no se pasa a la función.
'use strict'; const DEFAULT_HOST = "localhost"; class Foo { constructor(host = DEFAULT_HOST) { // ...start server console.log(`Server running on "${host}"`) } } var foo = new Foo(); // Server running on "localhost" var foo = new Foo('127.0.0.1'); // Server running on "127.0.0.1" function saveHost(host = DEFAULT_HOST) { // ...do save stuff console.log(`${host} saved to disk`) } saveHost() // localhost saved to disk saveHost('127.0.0.1') // 127.0.0.1 saved to diskLo más parecido que tiene JavaScript a los parámetros con nombre es la desestructuración. Donde pasamos en un objeto y se desestructura...
function foo({x: someX, y: someY}) { console.log(`SomeX is ${someX}. SomeY is ${someY}`); } foo({x: 5, y: 6})Ver también: ¿Nombres de parámetros con ES6?
Si quieres arreglar el código en tu comentario. Pruebe lo siguiente.
const DEFAULT_HOST = "localhost"; class B { constructor(host = null) { console.log(`HOST: ${host}`); } } class A { constructor() { new B(DEFAULT_HOST); } } new A(); // HOST: localhost new B(123); // HOST: 123 new B(); // HOST: null