这是一道考察React类组件继承原理和JavaScript的class继承机制的经典面试题。很多人知道要用super(props),但说不出具体原因。
下面从JavaScript原型链、React内部实现、以及实际影响三个层面来拆解。
一、核心结论
在React类组件中,
super(props)是标准写法,super()在某些情况下也能工作,但会导致this.props在构造函数中为undefined。
具体区别:
| 写法 | this.props在构造函数中的值 | 是否推荐 |
|---|---|---|
super() | undefined | ❌ 不推荐 |
super(props) | 传入的props对象 | ✅ 标准写法 |
二、JavaScript层面的原因
1. super()的作用
在ES6的class继承中,super()是调用父类的构造函数。
class Parent {
constructor(name) {
this.name = name;
}
}
class Child extends Parent {
constructor(name, age) {
super(name); // 调用 Parent.constructor
this.age = age;
}
}
规则: 在子类构造函数中,this必须在使用前通过super()初始化。不调用super()会报错。
2. super(props) vs super() 的差异
关键在于:父类(React.Component)的构造函数对props做了什么?
简化版的React.Component实现:
class Component {
constructor(props) {
this.props = props; // 将props挂载到实例上
// ... 其他初始化
}
}
super(props):将props传给父类构造函数 → 父类执行this.props = props→ 子类实例上有了props。super():没有传props→ 父类构造函数中this.props = undefined→ 子类实例上this.props是undefined。
三、React中的实际影响
场景1:在构造函数中访问this.props
class MyComponent extends React.Component {
constructor(props) {
super(); // ❌ 没有传props
console.log(this.props); // undefined
}
render() {
console.log(this.props); // ✅ 有值(React在渲染前会补上)
return <div>{this.props.name}</div>;
}
}
关键点:
- 构造函数中的
this.props是undefined。 render方法中的this.props有值,因为React在调用render之前会重新设置this.props。
场景2:在构造函数中使用this.props做初始化
class MyComponent extends React.Component {
constructor(props) {
super(props); // ✅ 正确
this.state = {
count: this.props.initialCount // 需要props
};
}
}
如果使用super(),this.props.initialCount就是undefined,导致初始化错误。
四、为什么super()在render中也能工作?
React内部在实例化组件后,会做额外的处理:
// React内部简化逻辑
const instance = new YourComponent(props); // 此时实例的this.props可能不正确
instance.props = props; // React会重新赋值一次
instance.state = ...;
所以即使构造函数中this.props是undefined,在调用render前React会把它纠正过来。
但这依赖React的内部实现,不是标准行为,不应该依赖。
五、为什么官方推荐super(props)?
- 保证构造函数中能正确使用
this.props
如果需要在constructor中读取props做初始化,super()会出错。 - 符合ES6规范
子类构造函数应该完整地传递参数给父类构造函数。 - 避免依赖React的“修复”行为
React的未来版本可能改变内部实现,依赖这种修复行为不安全。 - 代码可读性和一致性
显式传递props让意图更清晰。
六、类组件中的完整标准写法
class MyComponent extends React.Component {
constructor(props) {
super(props); // ✅ 必须这样写
// 现在可以安全地使用 this.props
this.state = {
value: this.props.initialValue || ''
};
}
render() {
// 这里访问 this.props 也没问题
return <div>{this.props.value}</div>;
}
}
七、面试中的常见追问
追问1:如果构造函数中不需要使用this.props,可以用super()吗?
答: 技术上可以,但不推荐。原因:
- 如果将来有人在构造函数中添加对
this.props的引用,代码会静默失败(得到undefined而不是报错)。 - 不符合React官方规范(文档明确要求
super(props))。 - 是一种“坏味道”,表明对继承机制理解不清。
追问2:函数组件中没有这个问题?
答: 对。函数组件没有constructor,也没有继承React.Component,所以不存在super调用。这也是函数组件更简单的原因之一。
追问3:如果忘记写super()会怎样?
答:
constructor(props) {
// 没有调用 super()
this.state = {}; // ❌ ReferenceError: Must call super constructor
}
JavaScript会直接报错,因为子类构造函数中必须在使用this前调用super()。
八、面试参考答案(精简版)
“
super(props)和super()的区别在于:super(props)会将props传递给父类React.Component的构造函数,让父类把props挂载到this.props上。而super()不会传递props,导致在子类的constructor中this.props是undefined。虽然在render方法中React会重新给this.props赋值,但官方仍然强制要求使用super(props),以确保构造函数中也能正确访问props,同时符合ES6的继承规范。”



