关于React中this指向丢失问题

由一个小例子由浅入深地分析,如下图所示,想要实现点击h1标签中的文字实现切换效果(即修改react状态来驱动页面渲染)

目录

你需要的关于类的一丢丢的基础 

重头戏,react中的this指向丢失问题

1. state1(this丢失):

 2. state2(解决办法1)

3. state3(第二种解决办法及问题)


你需要的关于类的一丢丢的基础 

<script>

        class Demo1 {
            change() {
                console.log(this)
            }
        }

        const d1 = new Demo1;
        d1.change();
        const x = d1.change;
        x();
        
        class Demo2 {
            change = function () {
                console.log(this)
            }
        }

        const d2 = new Demo2;
        d2.change();
        const y = d2.change;
        y();

</script>

 

上述代码中的四个console输出如上图所示;

  1. 首先执行d1.change(),新构建的实例d1中没有change方法,于是顺着原型链找到demo1的原型对象中的change方法,调用后打印this为Demo1 {}(即this指向新构建的实例d1)
  2. 然后执行const x = d1.change;  x();这两句是把Demo1原型中的方法change传给x,然后在调用x(),但是为什么打印this为undifined呢?因为类中的方法自动开启了严格模式,说人话就是当类中的方法在全局(window)调用的时候,指向this指向不再是window,而是undifined
  3. 再看到Demo2,这里就有意思了,在类中直接写了一个赋值语句,这是什么鬼?这种写法相当于给实例添加change方法.注意,change方法被添加进了实例d2中,不信你看第三行输出d1自带change方法然而第一行输出的d1就是个空的
  4. 最后一行输出,竟然是undifined,为啥?不是给d2身上添加了change方法了吗?没错,d2身上是由change方法了,但是执行const y = d2.change;  y();这相当于在全局调用d2上的方法change,参考第二条的严格模式,所以打印undifined,这便是万恶之源

重头戏,react中的this指向丢失问题

由于注释全写在代码中影响观看,故用索引

1. state1(this丢失):

<script type="text/babel">
        class Weather extends React.Component {
            constructor(props){
                super(props)
                this.state = {isHot:true,isOut:false};
            }
            render(){
                //@1
                return (<h1 onClick={this.changeWeather}>
                            今天天气{this.state.isHot ? '炎热' : '凉爽'},
                            我要{this.state.isOut ? '外出' : '呆在家'}
                        </h1>)
            }
            changeWeather(){
                //@2
                console.log(this);
            }
        }
        ReactDOM.render(<Weather/>,document.getElementById('test'))
    </script>

  1.  给h1标签绑定onclick,回调函数指向Weather原型对象中的方法changeWeather
  2.  当点击事件触发来到这儿的时候,react执行回调函数changeWeather,但是这儿打印的this是undifined,为啥?原来类中的方法在全局执行的时候(这里是把Weather类中的方法changeWeather交给react作为点击事件的回调函数时), 方法内的this是undifined,因为es6中所有方法自动开启了严格模式(即this不让指向window,直接指向undifined(如果看不懂可以参考class基础中的第二行输出,简单来说就是在全局中执行了changeWeather)

 

打印结果上图所示 


 2. state2(解决办法1)

<script type="text/babel">
        class Weather extends React.Component {
            constructor(props){
                super(props)
                this.state = {isHot:true,isOut:false};
                //@3
                this.changeWeather = this.changeWeather.bind(this);
            }
            render(){
                //@1
                //@4
                return (<h1 onClick={this.changeWeather}>
                            今天天气{this.state.isHot ? '炎热' : '凉爽'},
                            我要{this.state.isOut ? '外出' : '呆在家'}
                        </h1>)
            }
            changeWeather(){
                //@2
                //@5
                console.log(this.state);
                this.setState({isHot:!this.state.isHot});
                this.setState({isOut:!this.state.isOut});
            }
        }
        ReactDOM.render(<Weather/>,document.getElementById('test'))
    </script>
  1. 给h1标签绑定onclick,回调函数指向Weather原型对象中的方法changeWeather

  2. 当点击事件触发来到这儿的时候,react执行回调函数changeWeather,但是这儿打印的this是undifined. 原因:类中的方法在全局执行的时候(这里是把Weather类中的方法changeWeather交给react作为点击事件的回调函数时),方法内的this是undifined,因为es6中所有方法自动开启了严格模式(即this不让指向window,直接指向undifined)

  3. 重头戏来了!!!(bind是个好东西),以下是个骚操作

    需要知道的:constructor中的this指向Weather实例,changeWeather这个方法存在于Weather的原型中. 解决办法1:可以通过以下代码解决.这是一个赋值语句,看等号右边,首先通过this.changeWeather顺着原型找到changeWeather,然后调用bind方法 (注:demo.bind(this)相当于this.demo(),会返回一个拥有新的this指向的函数) 所以在这里调用bind(this),这个this在constructor构造器中指向实例.所以this.changeWeather.bind(this)返回了一个this指向Weather构造的实例的changeWeather函数;接着看等号左边,this.changeWeather即给实例一个属性changeWeather,而这个属性等于之前所说的等号右边返回的新函数(重点是新函数的this指向了实例) 总结:原理就是给实例追加一个属性,是一个函数,且这个函数的this指向实例

  4. 当调用onclick回调函数的时候,该回调函数是this.chanWeather即该实例上自带的属性,且this指向自身,大功告成!我们不就是想找回那些年我们失去的this吗

  5. 这时候打印this,指向的不再是undifined,而是Weather实例


其实第二个demo我们已经完美地解决了this的指向问题,但是!不够骚,不够装杯,接下来深入一层

3. state3(第二种解决办法及问题)

<script type="text/babel">
        class Weather extends React.Component {
            //@1
            state = {isHot:true,isOut:false};
            changeWeather = function(){
                //@2
                console.log(this);
            }
            render(){
                //@3
                return (<h1 onClick={this.changeWeather}>
                            今天天气{this.state.isHot ? '炎热' : '凉爽'},
                            我要{this.state.isOut ? '外出' : '呆在家'}
                        </h1>)
            }
        }
        ReactDOM.render(<Weather/>,document.getElementById('test'))
    </script>
  1. 在类中用a = 100 这种赋值语句的时候,相当于给类的实例追加a = 100这个属性,以下的state和changeWeather同理(这儿看不懂的可以参考class基础中的demo2)

  2. 这里的打印的结果是undifiend,因为就算是实例拥有了changeWeather这个方法,也必须通过this.changeWeather这种形式去调用,这样方法中的this才会指向实例.但是(接3.)

  3. 实例中的方法changeWeather作为onclick回调函数传给react(注意,this.changeWeather是函数,this.changeWeather()才是调用)

 3. state4(终究方案)

<script type="text/babel">
        class Weather extends React.Component {
            state = {isHot:true,isOut:false};
            //@1
            changeWeather = () => {
                console.log(this.state);
                this.setState({isHot:!this.state.isHot});
                this.setState({isOut:!this.state.isOut});
            }
            render(){
                return (<h1 onClick={this.changeWeather}>
                            今天天气{this.state.isHot ? '炎热' : '凉爽'},
                            我要{this.state.isOut ? '外出' : '呆在家'}
                        </h1>)
            }
           
        }
        ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>

解决state3中问题的方法,利用箭头函数(需要知道的:箭头函数没有this,在里面使用this会向外寻找this指向).

描述一下过程:

  1. react创建一个Weather实例(这个实例一创建便有了state状态属性和changeWeather方法,天赋拉满),我们假设这个实例是w
  2. 然后react调用w.render()返回一个h1标签,但是这个标签带有onclick事件,这个事件的回调函数是w身上的changeWeather.,而这个方法是个箭头函数,当事件触发的时候调用箭头函数,由于箭头函数没有this,向外寻找,找到了实例x,故箭头函数中的this指向实例x 
  3. 接下来执行changeWeather中的内容,this没丢失,如鱼得水,顺利地修改了实例的状态,补充一句:修改状态得调用x.setState(),而不能直接写x.state.isHot
  4. 修改完实例状态,接下来便是渲染了,简简单单

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值