youngwind/blog

在react中使用箭头函数引发的对this的思考

youngwind opened this issue · 6 comments

前言

用es6一段时间了,某次想把组件内部的函数都改写成箭头函数。比如

render : function(){
  console.log(this.props);
}

改写成下面这样的

render () => {
  console.log(this.props);  // 报错,this是undefined
}

结果显示this是undefined,我就感觉箭头函数的this有坑,研究了一番,发现还真的不一样。

箭头函数this指向与普通函数不同

箭头函数的this指向函数定义时的作用域,普通函数的this指向函数调用时的作用域。
因为箭头函数没有自己的上下文。
完整地例子参考这里:http://jsbin.com/vetecagupa/edit?js,console
注:在非严格模式执行

这个例子会输出1,因为普通函数的this指向函数被调用时候的作用域,也就是demo

var x = 10;
var demo = {
    x : 1,
    test1 : function() { console.log(this.x); },
    test2 : function() {
        this.test1();
    }
};

demo.test2();  // 1  

这个例子会输出10,因为test1函数在定义的时候处于global作用域,调用的时候this维持不变。

var x = 10;
var demo2 = {
    x : 1,
    test1 : () => { console.log(this.x); },
    test2 : function() {
        this.test1();
    }
};

demo2.test2();  // 10

这个例子会报错,因为函数test2定义的时候处于global作用域,所以调用的时候this指向global,而global中不存在test2方法。

var x = 10;
var demo3 = {
    x : 1,
    test1 : () => { console.log(this.x); },
    test2 : () =>{
        this.test1();
    }
};

demo3.test2();  // error: this.test1 is not a function

回到render函数

搞清楚了箭头函数的this问题,但是由于我还没搞清楚react定义组件的时候作用域的问题,所以暂时没办法搞明白如何在组件中使用箭头函数,以后有时间再研究研究,未完待续。。。。

cagen commented

可能的三种方案

  1. ES7 Property Initializers (Babel Stage 0提供):

    Class MyComponent extends React.Component {
      render = () => {
        console.log(this.props);
      }
    }
  2. Autobind Decorator:

    import autobind from 'autobind-decorator';
    
    Class MyComponent extends React.Component {
      @autobind
      render () {
        console.log(this.props);
      }
    }
  3. 构造函数里头手动绑定:

    Class MyComponent extends React.Component {
      constructor() {
        this.render = this.render.bind(this);
      }
      render() {
        console.log(this.props);
      }
    }

@cagen thanks!

@youngwind 谢谢你提出的问题
@cagen 谢谢你的回答
也可以通过安装babel-plugin-transform-class-properties插件解决这个问题

class Header extends React.Component {
    handleClick = (e) => {
        console.log(e);
    }
    render() {
        return (
            <div>
                    <button type="button" onClick={this.handleClick}>点击</button>
            </div>
        )
    }
}

具体使用方法,可以到Babel官网查看

var demo2 = {
x : 1,
test1 : () => { console.log(this.x); },
test2 : function() {
this.test1();
}
};
这个test1怎么是定义在全局的,这不是再demo2里面定义的吗

var demo2 = {
x : 1,
test1 : () => { console.log(this.x); },
test2 : function() {
this.test1();
}
};
这个test1怎么是定义在全局的,这不是再demo2里面定义的吗

test1 依然是demo2的属性,但是调用时箭头函数里的this指向的是全局对象。