关于React中事件处理的问题之bind(this)和ES6中的class渊源

        对于新手学习React中事件处理这一章节,大多数会在使用bind(this)绑定this这个操作上深感疑惑。最近被问到这个问题,感觉没有通俗易懂的语言能够讲清楚这个知识点。于是去React官网上看了一下官网的解释和网上一些其他的说法之后,感觉能把初学者整跑路。

        所以自己就来这里记录一下了,希望对于初学者来说有帮助。这里我们先来看一个简单的案例,案例里我们定义了一个有状态组件Hello,在这个组件里我们定义了一个updateInfo方法。要想使用this.updateInfo这个函数方法就必须在constructor中去使用bind(this)方法绑定this,否则this就是undefined。

    class Hello extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                age: 13,
                flag: true
            }
            this.updateInfo = this.updateInfo.bind(this)
        }

        // 如果使用函数的形式直接定义,要在constructor里面去绑定this改变this的指向
        updateInfo() {
            console.log(this)
            this.setState({
                age: 5
            })
        }
        render() {
            return <div>
                    <p>这是一个有状态组件</p>
                    <p>年龄:{this.state.age}</p>
                    <button onClick={this.updateInfo}>更新年龄</button>
                </div>
        }
    }

问题就此产生了,为什么要绑定this才能用呢?其实这里我们最去了解一下在咱们ES5中的构造函数和ES6的类的概念,这个问题的答案就非常通俗易懂了。

首先我们来看一下以下代码案例,大家注意看里面的注释,这段代码的精髓都在注释里了:

        // js中构造函数的写法
        function Person(x, y) {
            this.x = x
            this.y = y
        }
        Person.prototype.add = function() {
            console.log(this.x+this.y)
        }
        let p = new Person(1, 2)

        // 上面的代码用ES6的class改写,就是下面这样
        class Persons {
            constructor(x, y) {
                this.x = x
                this.y = y
            }
            add() {
                console.log(this.x+this.y)
            }
        }
        // 这个时候我们来看一下Persons的类型以及Persons这个类跟构造函数的关系
        typeof Persons // "function"
        Persons === Persons.prototype.constructor // true
        // 我们发现Persons类的数据类型就是函数,类本身就指向构造函数
        // 由此可见,构造函数的prototype属性,在ES6的class里同样存在着

所以通过上面的代码我们能够得出的结论是:类的所有方法都定义在类的prorotype上面

        class Persons {
            constructor() {}
            add() {}
        }
        // 等同于
        Persons.prototype = {
            constructor() {},
            add() {}
        }

在这个实例代码中我们能看到,constructor()、add()其实都是定义在Persons.prototype上。所以,在类的实例上调用方法,其实就是调用原型上的方法。这里我们还可以用一个案例来验证一下:

        class Hello{}
        let h = new Hello()
        h.constructor === Hello.prototype.constructor // true
        // h是Hello的实例,它的constructor()方法就是Hello类原型的constructor()方法

所以在ES6的类中,跟ES5是一样的是,实例的属性只有定义在自身的时候(也就是通过this.属性这种形式)是定义在this对象上,其他都是定义在原型上(即定义在class上)。

下面我们再来看一个案例代码:

        class Hello {
            constructor(x, y) {
                this.x = x
            }
            add() {
                console.log(this.x);
            }
        }
        var hello = new Hello(2);
        hello.add() // 2
        // 我们用hasOwnProperty看看对象自身属性中是否具有指定的属性
        hello.hasOwnProperty('x') // true
        hello.hasOwnProperty('add') // false
        hello.__proto__.hasOwnProperty('add') // true

add方法被定义在了原型上面,所以这个时候如果想要add方法变成对象自身的方法,就需要去改变this指向,也就回到了我们文章开始的案例那样,使用bind(this)方法进行绑定:

        class Hello {
            constructor(x, y) {
                this.x = x
                this.add = this.add.bind(this)
            }
            add() {
                console.log(this.x);
            }
        }
        var hello = new Hello(2);
        hello.add() // 2
        hello.hasOwnProperty('x') // true
        hello.hasOwnProperty('add') // true
        hello.__proto__.hasOwnProperty('add') // true

到这里大家应该明白了为什么要绑定this了吧,当然了,在React当中绑定this的方法有好几种,大家弄清楚了这一种之后,其他的也就懂了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值