小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
函数式组件和类式组件
React 创建组件的方式有两种,一种是函数式组件适用于简单组件的定义,一种是类式组件适用于复杂组件的定义。类式组件强大的地方在于它的 this,React.Component
上面就挂载了很多 React 自己定义的属性和方法。
函数式组件
// 1. 创建函数式组件
function MyComponent() {
// 此处的 this 是 undefined,因为 babel 编译后开启了严格模式。
console.log(this);
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
// 2.渲染组件到页面
ReactDOM.render(<MyComponent/>, document.getElementById('test'));
复制代码
执行了 ReactDOM.render(<MyComponent/>...
之后,发生了什么?
- React 解析组件标签,找到了
MyComponent
组件。 - 发现组件是使用函数定义的,随后调用该函数,将返回的
虚拟 DOM
转为真实DOM
,随后呈现在页面中。
类式组件
// 1. 创建类式组件
class MyComponent extends React.Component {
render() {
// render 是放在哪里的?MyComponent 的原型对象上供实例使用。
// render 中的 this 是谁?MyComponent 的实例对象 = MyComponent组件实例对象
console.log('render中的this', this)
return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
}
}
// 2. 渲染组件到页面
ReactDOM.render(<MyComponent/>, document.getElementById('test'));
复制代码
执行了 ReactDOM.render(<MyComponent/>...
之后,发生了什么?
-
React 解析组件标签,找到了
MyComponent
组件。 -
发现组件是使用类定义的,随后 new 出来该类的实例,并通过实例调用到该原型上的 render 方法。
-
将 render 返回的
虚拟DOM
转为真实DOM
,随后呈现在页面中。
ES6 中的类和继承
类的创建
class Person {
constructor(name) {
// 实例属性(可以传参):在构造函数内部定义,定义在实例对象(this)上的属性。
this.name = name;
}
// 实例属性(不可以传参)
age = '24'
// 静态属性:指的是 Class 本身的属性,即 `Class.propName`,而不是定义在实例对象(this)上的属性。
static company = 'google';
// 静态方法:static 关键字表示该方法不会被实例继承,而是直接通过类来调用
static sayHello() {
return 'hello';
}
// 实例方法:定义在实例对象(this)上的方法。
sayName() {
return 'hello, I am ' + this.name;
}
}
let kevin = new Person('Kevin');
console.log(Person.company); // 'google'
console.log(Person.sayHello()); // 'hello'
console.log(kevin.sayName()); // 'hello, I am Kevin'
复制代码
类的继承
class Parent {
constructor(name) {
this.name = name;
}
sayName() {
return 'hello, I am ' + this.name;
}
}
class Child extends Parent {
constructor(name, age) {
// 调用父类的 constructor(name)
super(name);
this.age = age;
}
}
let child = new Child('kevin', '18');
console.log(child); // {name: 'kevin', age: '18'}
console.log(child.sayName()); // 'hello, I am Kevin'
复制代码
super
关键字表示父类的构造函数,相当于 ES5 的 Parent.call(this)
。
子类必须在 constructor
方法中调用 super
方法,否则新建实例时会报错。这是因为子类没有自己的 this
对象,而是继承父类的 this
对象,然后对其进行加工。如果不调用 super
方法,子类就得不到 this
对象。
也正是因为这个原因,在子类的构造函数中,只有调用 super
之后,才可以使用 this
关键字,否则会报错。
Parent
上 sayName
实例方法的定义相当于 Parent.prototype.sayName = ...
,因此由上图也可以看出,实例方法挂载在 Parent
原型上,供所有的实例共享,实例方法内部 this 环境由当时调用的对象决定。