super() 和 super(props) 有什么区别?
问题解析(面试官考察点)
面试官通过此问题主要考察:
- 对 ES6 类继承机制的理解
- 对 React 类组件构造函数执行流程的掌握
- 是否了解 this 的绑定时机
- 对 React 内部实现的一定了解
核心概念(基础知识点)
ES6 中的 super
在 ES6 中,通过 extends 关键字实现类的继承,super 代表父类的构造函数:
class Sup {
constructor(name) {
this.name = name;
}
printName() {
console.log(this.name);
}
}
class Sub extends Sup {
constructor(name, age) {
super(name); // 调用父类构造函数
this.age = age;
}
printAge() {
console.log(this.age);
}
}
let jack = new Sub("jack", 20);
jack.printName(); // 输出: jack
jack.printAge(); // 输出: 20
为什么必须使用 super()
子类没有自己的 this 对象,必须继承父类的 this 对象:
class Sub extends Sup {
constructor(name, age) {
// 错误:必须先调用 super 才能使用 this
this.age = age; // ReferenceError: Must call super constructor
super(name);
}
}
详细解答(代码示例)
React 类组件中的 super()
class Button extends React.Component {
constructor(props) {
super(); // 没有传入 props
console.log(props); // {} - 参数可以访问
console.log(this.props); // undefined - this.props 未定义
}
}
React 类组件中的 super(props)
class Button extends React.Component {
constructor(props) {
super(props); // 传入了 props
console.log(props); // {} - 参数可以访问
console.log(this.props); // {} - this.props 已定义
}
}
没有 constructor 的情况
class HelloMessage extends React.Component {
render() {
// 没有 constructor,this.props 仍然可以访问
return <div>nice to meet you! {this.props.name}</div>;
}
}
推荐写法
class MyComponent extends React.Component {
constructor(props) {
super(props); // 推荐写法
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>Props: {this.props.title}</p>
<p>State: {this.state.count}</p>
</div>
);
}
}
深入理解(原理剖析)
React 内部如何处理 props
React 内部实现大致如下:
// React 内部伪代码
const instance = new YourComponent(props);
instance.props = props; // 在构造函数执行后才赋值
这意味着:
- 如果不传递
props给super(),this.props在构造函数执行期间是undefined - React 会在构造函数执行完毕后给
this.props赋值
执行时序分析
class Button extends React.Component {
constructor(props) {
// 1. super() 执行前:this 不存在
super(props);
// 2. super(props) 执行后:this 存在,this.props = props
console.log(this.props); // 可以访问
// 3. 构造函数执行完毕
// 4. React 内部:instance.props = props(如果没有传 props)
}
}
使用场景对比
| 场景 | 使用 super() | 使用 super(props) |
|---|---|---|
| 构造函数中访问 this.props | undefined | 可以访问 |
| render 中访问 this.props | 可以访问 | 可以访问 |
| 其他生命周期访问 this.props | 可以访问 | 可以访问 |
为什么建议使用 super(props)
- 符合逻辑:确保
this.props在构造函数执行完毕之前已被赋值 - 避免错误:如果在构造函数中需要使用
this.props,不会得到undefined - 代码一致性:统一写法,避免混淆
最佳实践
推荐写法
class MyComponent extends React.Component {
constructor(props) {
super(props); // 始终传递 props
this.state = {
// 初始状态
};
}
}
简化写法(不需要 constructor)
class MyComponent extends React.Component {
state = {
count: 0
};
render() {
return <div>{this.props.title}</div>;
}
}
箭头函数绑定(不需要 constructor)
class MyComponent extends React.Component {
state = {
count: 0
};
handleClick = () => {
// 自动绑定 this
console.log(this.props.title);
};
render() {
return <button onClick={this.handleClick}>Click</button>;
}
}
使用函数组件(推荐)
function MyComponent(props) {
const [count, setCount] = useState(0);
return (
<div>
<p>{props.title}</p>
<p>{count}</p>
</div>
);
}
面试要点
-
核心区别
super():父类构造函数执行后,this.props为undefinedsuper(props):父类构造函数执行后,this.props已赋值
-
ES6 类继承规则
- 子类必须在
constructor中先调用super()才能使用this super()相当于调用父类的构造函数
- 子类必须在
-
React 的特殊处理
- 无论是否写
constructor,React 都会自动处理props - 在
render和其他生命周期中,this.props总是可以访问
- 无论是否写
-
常见误区
- 不写
constructor时,this.props仍然可以访问(React 自动处理) - 写了
constructor但不传props给super,构造函数中this.props为undefined
- 不写
-
现代 React 建议
- 优先使用函数组件 + Hooks
- 类组件中尽量省略
constructor,使用类属性语法 - 如果必须写
constructor,始终使用super(props)
-
相关面试题
- 为什么类组件需要写 super?
- super() 和 super(props) 的区别?
- 不写 constructor 可以访问 this.props 吗?
- 在 constructor 中调用 this.props 有什么风险?