When I try to specify the parameter names when calling a function from inside a JavaScript class constructor, I get a ReferenceError
.
I will show the problem based on a simplified example:
Suppose I have an object and methods like so:
class Person {
constructor(name, age) {
this.name = name,
this.age = age
}
addYear() {
this.age ;
}
changeName(newName) {
this.name = newName;
}
changeAge(newAge) {
this.age = newAge;
}
changeAgeAndName(newName, newAge) {
this.changeName(newName=newName);
this.changeAge(newAge=newAge);
}
}
All works fine if I instanciate it, and if mingle with it a bit this is the code and output:
let p1 = new Person('George', 20);
console.log(p1);
p1.changeName(newName='Robert');
console.log(p1);
p1.changeAgeAndName(newName='Joe', newAge=23);
console.log(p1);
Person { name: 'George', age: 20 }
Person { name: 'Robert', age: 20 }
Person { name: 'Joe', age: 23 }
Now, let's say I want to use changeAgeAndName inside the constructor like so (specifying the parameter names for the variables):
constructor(name, age) {
this.changeAgeAndName(newName=name, newAge=age);
}
I get an error:
this.changeAgeAndName(newName=name, newAge=age);
ReferenceError: newName is not defined
But if I don't specify the parameter names, all is fine:
constructor(name, age) {
this.changeAgeAndName(name, age);
}
Eventual Output:
Person2 { name: 'Mike', age: 40 }
If I specify the parameter names outside the constructor, all is fine as well. I like to be as explicit as possible when coding, so I was wondering what I may be doing wrong. Also, I was curious about perhaps yet another example of peculiar JS behavior. Thank you!
CodePudding user response:
When you called:
p1.changeAgeAndName(newName='Joe', newAge=23);
you thought you were specifying that the newName
argument should be 'Joe'. What you are actually doing is implicitly declaring a new variable, setting the result to 'Joe', and passing the string 'Joe' as the first argument to the function. That function does not care about anything other than argument position.
If you want to name your variables for clarity, do:
changeAgeAndName({newName, newAge}) {
//...
}
and call it with:
this.changeAgeAndName({newName: 'Joe', newAge: '23'});
As noted by @NickParsons, all parts of a class's body are in 'strict mode'. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode#strict_mode_for_classes
Therefore, your ReferenceError is caused by your implicit variable declaration (doing newName='Joe'
) without first declaring the variable with let newName
. Implicit variable declaration is not allowed in strict mode.
CodePudding user response:
So it turns out I was actually fooling myself and the problem goes beyond the constructor and strict mode. The problem is that JS doesn't at all have named arguments (I should have known that but I didn't mess with it until just recently). The arguments will still be read in the default order as declared when creating the function. I think it would be better for JS to reject any sort of attempt to name variables when calling a function. That would provide clarity.
If you want to be explicit in naming arguments, the solution is "parameter destructing" as described here: Is there a way to provide named parameters in a function call in JavaScript?
Thanks to @Nick Parsons and @Andrew Parks
CodePudding user response:
do p1.changeAgeAndName(newName,newAge)