1.class
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
特点
1. 类的所有方法都定义在类的 prototype 属性上面
class Point {
constructor() {
// …
}
}
==
Point.prototype = {
constructor() {},
};
2.Point.prototype.constructor === Point // true3. 定义“类”的方法的时候,前面不需要加上 function 这个关键字,直接把函数定义放进去了就可以了 4. 类不存在变量提升(hoist),这一点与 ES5 完全不同。5. 类的方法内部如果含有 this,它默认指向类的实例 6. 如果在一个方法前,加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静 态方法”。7. 写法
ES5 写法
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return ‘(‘ + this.x + ‘, ‘ + this.y + ‘)’;
};
var p = new Point(1, 2);
ES6
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return ‘(‘ + this.x + ‘, ‘ + this.y + ‘)’;
}
}
2.constructor()——构造方法
这是 ES6 对类的默认方法,通过 new 命令生成对象实例时自动调用该方法。并且,该方法是类中必须有的,如果没有显示定义,则会默认添加空的 constructor()方法。
1.constructor 方法默认返回实例对象(即 this)
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
point.hasOwnProperty(‘x’) // true
2.super() ——继承
在 class 方法中,继承是使用 extends 关键字来实现的。子类 必须 在 constructor()调用
super()方法,否则新建实例时会报错。
在 constructor 中必须调用 super 方法,因为子类没有自己的 this 对象,而是继承父类的 this 对象
,然后对其进行加工, 而 super 就代表了父类的构造函数。super 虽然代表了父类 A 的构造函数,
但是返回的是子类 B 的实例,即 super 内部的 this 指的是 B,因此 super() 在这里相当于
A.prototype.constructor.call(this, props)。
class A {}
class B extends A {
constructor() {
super(); // ES6 要求,子类的构造函数必须执行一次 super 函数,否则会报错。
}
}
3. 如果你在 constructor 中要使用 this.props, 就必须给 super 加参数:super(props);
3.ref 和 React.js 中的 DOM 操作
顺带一提的是,其实可以给组件标签也加上 ref
<input ref={(input) => this.input = input} />//input 为获取的节点
4.react 组件可内嵌组件或者节点原理
嵌套的结构在组件内部都可以通过 props.children 获取到
class Card extends Component {
render () {
return (
<div className=’Card’>
<div className=’0′>
{this.props.children[0]}
</div>
<div className=’1′>
{this.props.children[1]}
</div>
</div>
)
}
}
ReactDOM.render(
<Card>
<div>children[0]</div>
<div>children[1]</div>
</Card>,
document.getElementById(‘root’)
)
5. 默认配置 defaultProps&& 给组件的配置参数加上类型验证
class LikeButton extends Component {
static defaultProps = {
likedText: ‘ 取消 ’,
unlikedText: ‘ 点赞 ’
}
static propTypes = {
comment: PropTypes.object//const {comment} = this.props
}
static propTypes = {
comment: PropTypes.object.isRequired
}
}
6.react 中 bind(this)的理解
bind 返回值是由指定的 this 值和初始化参数改造的原函数拷贝在 JSX 中传递的事件不是一个字符串,而是一个函数(如:onClick={this.handleClick}),此时 onClick 即是中间变量,所以处理函数中的 this 指向会丢失。解决这个问题就是给调用函数时 bind(this),从而使得无论事件处理函数如何传递,this 指向都是当前实例化对象。当然,如果不想使用 bind(this),我们可以在声明函数时使用箭头函数将函数内容返回给一个变量,并在调用时直接使用 this. 变量名即可
1
<button onClick={this.handleClick.bind(this)}> 有 bind 点击一下 </button>
2
constructor(props) {
super(props);
this.state = {
};
this.handleClick=this.handleClick.bind(this)
}
3
<button onClick={()=>{this.handleClick()}>
7. 高阶组件
高阶组件是一个函数(而不是组件),它接受一个组件作为参数,返回一个新的组件。这个新的组件会使用你传给它的组件作为子组件
import React, {Component} from ‘react’
export default (WrappedComponent, name) => {
class NewComponent extends Component {
constructor () {
super()
this.state = {data: null}
}
componentWillMount () {
let data = localStorage.getItem(name)
this.setState({data})
}
render () {
return <WrappedComponent data={this.state.data} />
}
}
return NewComponent
}
import wrapWithLoadData from ‘./wrapWithLoadData’
class InputWithUserName extends Component {
render () {
return <input value={this.props.data} />
}
}
InputWithUserName = wrapWithLoadData(InputWithUserName, ‘username’)
export default InputWithUserName
8.export&&import
模块功能主要由两个命令构成:export 和 import。export 命令用于规定模块的对外接口,import 命令用于输入其他模块提供的功能。一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用 export 关键字输出该变量
1.export 命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系 2.export 语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值 3. 注意输出时 {} 的使用表明其是一个接口,不用则为值会报错
//export var year = 1958;
var firstName = ‘Michael’;
var lastName = ‘Jackson’;
var year = 1958;
export {firstName, lastName, year};
———-
// 报错
export 1;
// 报错
var m = 1;
export m;
———-
// 写法一
export var m = 1;
// 写法二
var m = 1;
export {m};
// 写法三
var n = 1;
export {n as m};
// 函数
function f() {}
export {f};
4.import 命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同 5. 如果想为输入的变量重新取一个名字,import 命令要使用 as 关键字,将输入的变量重命名 6.import 命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写 接口 7. 注意,import 命令具有提升效果,会提升到整个模块的头部,首先执行 8.import 是静态执行,所以不能使用表达式和变量
import {lastName as surname} from ‘./profile.js’;
import {myMethod} from ‘util’;//util 是模块文件名,必须通过配置,告诉引擎怎么取到这个模块
import ‘lodash’;//import 语句会执行所加载的模块
9. 模块的整体加载
除了指定加载某个输出值,还可以使用整体加载,即用星号(*)指定一个对象,所有输出值都加载在这个对象上面。
// circle.js
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
import * as circle from ‘./circle’;
console.log(‘ 圆面积:’ + circle.area(4));
console.log(‘ 圆周长:’ + circle.circumference(14));
10.export default 命令,为模块指定默认输出
// export-default.js
export default function () {
console.log(‘foo’);
}
// import-default.js
import customName from ‘./export-default’;
customName(); // ‘foo’
1. 使用 export default 时,对应的 import 语句不需要使用大括号
// 第一组
export default function crc32() { // 输出
// …
}
import crc32 from ‘crc32’; // 输入
// 第二组
export function crc32() { // 输出
// …
};
import {crc32} from ‘crc32’; // 输入
// 结合使用
import _, {each, forEach} from ‘lodash’;
2.export default 命令其实只是输出一个叫做 default 的变量,所以它后面不能跟变量声明语句
// 正确
export var a = 1;
// 正确
var a = 1;
export default a;
// 错误
export default var a = 1;
11. 解构赋值
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [, , third] = [“foo”, “bar”, “baz”];
third // “baz”
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, …tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, …z] = [‘a’];
x // “a”
y // undefined
z // []
1. 如果等号的右边不是数组(或者严格地说,不是可遍历的结构,参见《Iterator》一章),那么将会报错
// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
2. 解构赋值允许指定默认值
let [foo = true] = [];
foo // true
let [x, y = ‘b’] = [‘a’]; // x=’a’, y=’b’
let [x, y = ‘b’] = [‘a’, undefined]; // x=’a’, y=’b’
3. 解构不仅可以用于数组,还可以用于对象
// 简易模型
let {bar, foo} = {foo: “aaa”, bar: “bbb”};
foo // “aaa”
bar // “bbb”
let {baz} = {foo: “aaa”, bar: “bbb”};
baz // undefined
// 基本模型
var robotA = {name: “Bender”};
var robotB = {name: “Flexo”};
var {name: nameA} = robotA;
var {name: nameB} = robotB;
nameA//”Bender”
nameB//”Flexo”
// 多重解构
const node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
let {loc, loc: { start}, loc: {start: { line}} } = node;
line // 1
loc // Object {start: Object}
start // Object {line: 1, column: 5}
// 默认值
var {x, y = 5} = {x: 1};
x // 1
y // 5
var {message: msg = “Something went wrong”} = {};
//JavaScript 引擎会将 {x} 理解成一个代码块,从而发生语法错误
// 只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题
let x;
({x} = {x: 1});
// 字符解构
const [a, b, c, d, e] = ‘hello’;
a // “h”
b // “e”
c // “l”
d // “l”
e // “o”
12 箭头函数
箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值。这就意味着如果箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的 this。没有 arguments 不能通过 new 关键字调用没有原型没有 super
格式 1:多个参数
(param1, param2, …, paramN) => {statements}
// statements 应该有 return 语句
(param1, param2, …, paramN) => expression
// 相当于 return expression
格式 2:一个参数
(singleParam) => {statements}
singleParam => {statements} // 可以去掉括号
格式 3: 没有参数
() => { statements}
格式 4: 返回对象
params => ({foo: bar})
格式 5: 支持扩展符号
(param1, param2, …rest) => {statements}
格式 6: 支持默认值
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => {statements}
格式 7: 支持解构赋值
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; f(); // 6