React组件中foo(){}与bar=()=>{}的区别、适用场景及Babel疑问
嘿,这个问题问得特别到位,刚好是React开发里新手老手都容易搞混的点,我来给你唠明白~
两种方法定义的核心区别
1. this 指向天差地别
- 对于
foo() {}:这是传统的类原型方法,this的指向完全看调用它的方式。如果直接把它当事件处理函数用(比如<button onClick={this.foo}>),触发事件时this会直接变成undefined(严格模式下)——因为事件触发时是直接调用函数,不是通过组件实例调用的,自然丢了绑定。 - 对于
bar = () => {}:箭头函数本身没有自己的this,它会“抓”住定义时所在上下文的this(也就是组件实例),所以不管你怎么调用它,this永远指向当前组件实例,根本不会出现绑定丢失的问题。
2. 挂载位置完全不同(你的猜测完全正确!)
foo() {}:会被挂载到MyComponent的原型对象上。也就是说,所有MyComponent的实例都会共享同一个foo函数,内存占用特别高效,不会重复创建函数副本。bar = () => {}:这是ES6+的类实例属性语法,会在组件实例化的构造函数阶段,给每个实例单独创建一个箭头函数副本。简单说就是每个组件实例都有自己专属的bar,内存开销比原型方法要大一点。
3. Babel的转换逻辑拆解
你困惑的Babel转换其实没那么复杂,我给你拆成ES5代码看就懂了:
- 对于
foo() {},Babel会转成传统的原型方法:
function MyComponent(props) { // 组件构造函数原有逻辑 } // 把foo挂到原型上,所有实例共享 MyComponent.prototype.foo = function foo() { // 方法内容 };
- 对于
bar = () => {},Babel会把它转成构造函数里的实例属性,本质就是手动绑定this:
function MyComponent(props) { // 组件构造函数原有逻辑 // 给当前实例单独赋值一个绑定好this的函数 this.bar = (function() { // 方法内容 }).bind(this); }
相当于帮你在构造函数里做了this.bar = this.bar.bind(this)的操作,所以每个实例都有自己的bar。
该在什么时候用哪种?
优先用foo() {}的场景
- 当你能自己搞定
this绑定的时候:比如在构造函数里手动绑定this.foo = this.foo.bind(this),或者调用时用箭头函数包裹(<button onClick={() => this.foo()}>); - 当方法是给子类继承用的:原型方法可以被子类轻松重写或者通过
super.foo()调用,符合类的设计逻辑; - 当组件会被大量实例化的时候(比如列表里的子组件):共享原型方法能节省内存,避免不必要的性能损耗。
适合用bar = () => {}的场景
- 最常用的就是事件处理函数:直接把
this.bar传给onClick这类事件,不用额外做绑定,代码更简洁; - 当方法需要作为回调传递给子组件、定时器或者Promise的时候:箭头函数能确保
this始终指向组件实例,不用操心绑定丢失的问题; - 注意:如果组件是高频实例化的,尽量少用这种方式,避免内存浪费。
内容的提问来源于stack exchange,提问作者ZYinMD
相关产品推荐
相关产品推荐

