为何在JavaScript类构造函数内无法指定函数参数名?
JavaScript构造函数内带参数名调用方法报错的原因与解决
问题重现
先定义如下类:
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); } }
在类外部调用方法时,带参数名的写法能正常运行:
let p1 = new Person('George', 20); console.log(p1); // Person { name: 'George', age: 20 } p1.changeName(newName='Robert'); console.log(p1); // Person { name: 'Robert', age: 20 } p1.changeAgeAndName(newName='Joe', newAge=23); console.log(p1); // Person { name: 'Joe', age: 23 }
但在构造函数内使用同样写法调用changeAgeAndName时,会抛出错误:
class Person { constructor(name, age) { this.changeAgeAndName(newName=name, newAge=age); // 报错:ReferenceError: newName is not defined } // 其他方法同上 }
去掉参数名直接传值则正常运行:
class Person { constructor(name, age) { this.changeAgeAndName(name, age); // 正常执行 } // 其他方法同上 } let p2 = new Person('Mike', 40); console.log(p2); // Person { name: 'Mike', age: 40 }
原因分析
JavaScript根本没有「命名参数」这种语法,你之前写的newName='Robert'其实是赋值操作,不是指定参数名:
- 在类外部的普通代码里,非严格模式下给未声明的变量赋值会偷偷创建全局变量,所以不会报错,但这纯属巧合——因为你赋值的变量名刚好和方法参数名一致,而且传参顺序也对,所以结果看起来是对的。
- 但类的构造函数默认运行在严格模式下,严格模式禁止这种隐式创建全局变量的操作。当你在构造函数里写
newName=name时,JS会寻找newName这个变量,但你从未声明过它,直接就抛出ReferenceError了。
正确实现方式
如果想明确参数含义,给你两个靠谱的实现方式:
方案1:使用对象解构参数
把方法改成接受一个对象参数,通过解构获取值,调用时传入键值对对象,实现类似命名参数的效果:
class Person { constructor(name, age) { this.changeAgeAndName({ newName: name, newAge: age }); } changeName(newName) { this.name = newName; } changeAge(newAge) { this.age = newAge; } changeAgeAndName({ newName, newAge }) { // 对象解构获取参数 this.changeName(newName); this.changeAge(newAge); } } let p3 = new Person('Alice', 25); console.log(p3); // Person { name: 'Alice', age: 25 } // 外部调用时也能明确传参含义 p3.changeAgeAndName({ newName: 'Luna', newAge: 30 }); console.log(p3); // Person { name: 'Luna', age: 30 }
方案2:保留顺序+注释说明
如果不想修改方法参数结构,可以在调用时添加注释明确参数含义:
class Person { constructor(name, age) { // 对应参数:newName=name, newAge=age this.changeAgeAndName(name, age); } // 其他方法同上 }
内容的提问来源于stack exchange,提问作者Omri
相关产品推荐
相关产品推荐

