React.Component

原文来自:https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

先解释下问什么要翻译这篇文章:React16推出的新的生命周期,解决了一些问题。但这些新的生命周期本人实在是太陌生了。并且在用16版本的时候,本人几乎用不到这些新的生命周期。为了加深印象,决定翻译此文章。

这篇文章详细介绍了React组件类的API。假设你已经非常熟悉React的相关基础概念,比如说Component、Props、State和生命周期。如果你不理解,那就先弄懂它们。

概览

React允许你用类或者函数去定义一个组件。用类定义的组件可以提供很多特征,这些特征会在接下来讲到。你需要通过extends React.Component定义一个React组件类:

1
2
3
4
5
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}

这个组件类里,用户必须定义render的实现。其他方法是可选的。

React强烈反对构建自定义的基类组件。因为React中,代码复用的主要通过组合实现,并不是继承。

注意:
React不会强制用户使用ES6语法。如果你不想用ES6,也可以使用create-react-class模块或者类似的自定义抽象。你可以阅读:不用ES6写React

组件生命周期

组件都有生命周期的方法,这些方法允许你在一个阶段的某些特殊时期重载生命周期,运行自定义代码。你可以将生命周期图当做备忘录。

生命周期


下面这个列表中,经常用到的生命周期会用粗体表示。其他的很少用到。

挂载阶段

当一个组件实例被创建出来,并插入到DOM中,下面这些方法会按顺序执行:

  • constructor()
  • static getDerivedStateFromProps()
  • render()
  • componentDidMount()

    注意:
    下面的这些方法,是要被废掉的。因此在你的项目中,尽量避免使用它们。

    • UNSAFE_componentWillMount()

更新阶段

props和state的改变会引发更新。当组件重新调用render的时候,下面的方法会按序发生:

  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

    注意:
    下面的这些方法,是要被废掉的。因此在你的项目中,尽量避免使用它们。

    • UNSAFE_componentWillUpdate()
    • UNSAFE_componentWillReceiveProps()

卸载阶段

当组件从DOM节点中移出时,调用下面的方法:

  • componentWillUnmount()

错误处理

当render中发生异常时,会调用下面方法。异常捕获来自子节点的渲染中、生命周期中、构建中。

  • componentDidCatch()

其他API

组件同样提供了其他的方法:

  • setState()
  • forceUpdate()

类属性

  • defaultProps
  • displayName

实例属性

  • props
  • state

参考

常用生命周期

这一节里列举的方法在你的项目中会经常使用。可视化参考,你可以看生命周期图

render()

一个组件类,必须实现它的render方法。
当它被调用时,render会检查this.props和this.state,同时返回下面其中一个类型:

  • React elements。典型的是通过JSX创建。比如说,<div /><MyComponent />都是React elements,它们分别指导React渲染DOM节点和用户自定义组件。
  • Arrays and fragments。允许你通过render返回多个elements。阅读文档fragments
  • Portals。允许你在另外一个DOM节点渲染组件。阅读文档portals
  • String and numbers。做为文本节点渲染到DOM中。
  • Booleans or null。渲染空。(当test是boolean类型是,支持return test && <Child />这种形式。)

render()必须是纯函数,意味着render不能修改state。当state,props一致的时候,render返回的永远是一样的。并且render并不会与浏览器直接交互。
如果你需要和浏览器交互,应该在componentDidMount或者其他生命周期里实现。保证render是纯函数可以让思维更加简洁。

注意:
当shouldComponentUpdate()返回false时。render不会调用。

constructor()

如果你不需要初始化state,或者绑定事件,你就不需要实现你的constructor
React组件在挂载之前,会调用constructor。组件的constructor调用里,super(props)必须在所用语句前调用。否则,在constructor里,this.props返回undefined,从而导致bug。

通常,constructor主要用于下面两种目的:

  • 初始化state
  • 绑定事件
    在constructor里,你不能调用setState。如果组件需要一个本地状态,只需要在constructor里直接对this.state赋值即可:
    1
    2
    3
    4
    5
    6
    constructor(props) {
    super(props);
    // Don't call this.setState() here!
    this.state = { counter: 0 };
    this.handleClick = this.handleClick.bind(this);
    }

this.state这种直接赋值的方式,只能出现在constructor里。也就是说,其它地方,你只能使用this.setState()
为了避免在constructor里引入其它副作用,对于某种情况,你可以写在componentDidMount()里。

注意:避免将props拷贝到state中!下面案例在某些场景里会出现问题

1
2
3
4
5
constructor(props) {
super(props);
// Don't do this!
this.state = { color: props.color };
}

上面的问题非常没有必要,并且会产生bug。因为可以直接从props中获取color属性,为什么要多创建一个state呢;另外,因为在constructor中初始化的,所以后续对color的更新,不会反馈到state中。但是上面的情况只是在某些案例中会有问题。
如果你本来就要忽略props的更新,你可以用这种方式。在那种情况下,将props.color重命名为initialColor或者defaultColor会更加说的通。如果你想重置这个组件的初始状态,你可以改变他的key值。
我们将某些依赖于props的state叫做派生状态。可以阅读avoid derived state,了解更多。

componentDidMount()

componentDidMount在组件插入DOM之后,立即被调用。DOM的初始化操作,也是在这个函数中实现的。如果你需要从远程拉取数据初始化,componentDidMount是最好实现的地方。
同样,关于订阅的一些方法,也在这里设置。如果你订阅了方法,记得在componentWillUnmount里取消订阅。例如:如果你在componentDidMount设置了setTimeout句柄,那你就在componentWillUnmount里对这个句柄clearTimeout。

componentDidMount里如果立即调用setState,会立刻触发额外的render,但这个render发生在浏览器渲染到屏幕之前。这样就能确保:即便render在这个情况下调用了两次,用户没法看到中间状态(PS:不太理解这句话,但是render可能是在浏览器渲染之前调用,因为只有render调用了,才能返回对应的类型,去指导浏览器做出相应的渲染。如果在浏览器更新之后调用,render返回的新的VNode,为了状态与视图一致,势必会再次渲染浏览器。)。这种方式需要小心使用,因为这经常会产生性能问题。大多数情况下,你其实可以将这个初始状态在constructor里实现。
但是,在某些情况下:比如需要依赖获取提示信息的位置,设置state时,你只能在componentDidMount里去获取并setState。

componentDidUpdate()

1
componentDidUpdate(prevProps, prevState, snapshot)

componentDidUpdate()会在update发生之后立即调用。这个方法不会发生在第一次render之后。
通常,我们会在这里操作DOM。同样,由于当前props和之前props不同,调用远程接口,在componentDidUpdate里实现也是很好的实践:

1
2
3
4
5
6
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}

你可以在componentDidUpdate直接调用setState,但是必须在一个条件里,如比上面栗子所示。否则,就会死循环。同时,他也会造成额外的render,即便这些render用户不可见,但是对应用也造成了性能影响。如果你想『镜像』一些来自props的state,你可以考虑直接使用props。请阅读:why copying props into state causes bugs

如果组件里实现了getSnapshotBeforeUpdate的生命周期,这个getSnapshotBeforeUpdate返回的值会做为componentDidUpdate的第三个参数:”snapshot”,否则这个值就是undefined。

注意:
如果shouldComponentUpdate()返回的是false,componentDidUpdate不会被调用。

componentWillUnmount

在组件卸载,销毁之前,componentWillUnmount会被调用。componentWillUnmount里实现所有清理流程,比如clearTimeout, removeEventListener,cancel请求。
在componentWillUnmount里,不要调用setState,因为这时的setState不会产生额外的render。一旦一个组件卸载掉了,他就永远不可能再次挂载。这个组件就永远的走了。。。

不常用的生命周期

这一节里的方法不经常用。偶尔用他们会很方便,但是大多数组件都不太会用。在生命周期图里,你可以通过勾选『显示不常用的生命周期』看到他们。

shouldComponentUpdate

利用shouldComponentUpdate告知React当前的state或props的改变是否会影响到组件的输出。默认情况下,只要改变props或state都会重新调用render。并且大多数情况,你可以不用改这个函数,采用他的默认行为即可。
当新的props和state接受到时,shouldComponentUpdate在render之前调用。默认返回的是true。这个方法在初次render或者forceUpdate的时候,是不会被调用的。
当需要性能优化的时候,往往会用到shouldComponentUpdate。不要为了阻止重新render去用这个函数,因为这很可能会产生bug。如果在你需要手写shouldComponentUpdate的情况下,考虑使用PureComponent替换。PureComponent会做浅层的props,state比较,从而减少你跳过必要更新到可能。
如果你一定要手写shouldComponentUpdate,你可以比较this.props和nextProps,this.state和nextState。返回false,告知React这次的更新需要忽略掉。需要注意的是,父元素的return false不会影响到子元素state改变造成的render
我们非常不赞成在shouldComponentUpdate使用深比较或者利用JSON.stringify()比较,这会非常影响性能。
目前,如果shouldComponentUpdate返回false,UNSAFE_componentWillUpdate(), render(), 和 componentDidUpdate() 都不会被调用。未来,React会将shouldComponentUpdate视为一个提示,而不是严格的指令。这样,即便它返回的是false,也会使组件再次调用render。

static getDerivedStateFromProps()

1
static getDerivedStateFromProps(props, state)

翻译成中文:从props中得到派生状态。由此可见,派生状态依赖于props。getDerivedStateFromProps发生在render之前,发生在第一次render和更新触发的render之前。他返回的是一个对象更新state;或者也可以返回null,表示什么也不更新。
当状态随着时间的变化,依赖于props的改变,getDerivedStateFromProps才会被用到。比如说,利用它会非常方便实现<Transition>。因为他需要比较<Transition>之前的chldren和改变之后的chldren,来决定哪些需要淡入,淡出。
派生状态会导致代码变得冗长,使得你很难思考组件的逻辑。但是,你可以使用其它更简便的方式替换:

  • 如果由于props的改变,你需要操作一个副作用(比如,抓取数据或动画),你可以在componentDidUpdate里实现。
  • 如果当props改变,你需要重新计算某些值得时候,利用带有记忆的辅助函数
  • 如果当props改变时,你需要重置某些状态,可以考虑将组件转变为傻瓜组件,或者改变这个组件的key值。

getDerivedStateFromProps无法获取组件的实例,即在getDerivedStateFromProps里,this返回的是undefined。如果你愿意,你可以通过组件的props和state提取出以props和state为参数的纯函数,在getDerivedStateFromProps和其他类方法之间实现代码复用。
这个方法会在每次render都之前无条件触发。这个会与UNSAFE_componentWillReceiveProps形成对比,UNSAFE_componentWillReceiveProps只会在父组件render的时候才会被触发,并不会因为setState而触发

getSnapshotBeforeUpdate()

1
getSnapshotBeforeUpdate(prevProps, prevState)

getSnapshotBeforeUpdate在最近一次输出的render被committed到DOM之前调用,即发生在DOM更新之前。它允许你从DOM那,在DOM改变之前获取一些信息,比如说当时的scroll的位置。这个函数返回的值会做为componentDidUpdate的参数。
getSnapshotBeforeUpdate不会经常用到,但是在某些交互的场景下会用到。比如说一个聊天的线程需要处理scroll的位置。
这个函数必须返回一个snapshot值或者(null)。比如说:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}

getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
// 如果我们向list中添加一个item,我们会先记录下当前scroll的值,
// 用在后面的地方
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}

componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
// 如果能获取到snapshot,就表示我们刚才添加了一个item。
// 我们需要调整scroll,这样这些新加的items就不会将原来老的推出到屏幕之外了。
// snapshot是来自于getSnapshotBeforeUpdate
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}

render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}

栗子:在render调用之后,DOM更新之前,获取一个距离。在DOM更新之后,根据当时计算出的距离,重置scrollTop。从理解上来看,栗子想表达的意思是我们每增加一个item,scroll都会向上移动新增item高度的距离。
在上面的例子中,scrollHeight必须在getSnapshotBeforeUpdate计算。因为在『render』和『commit』阶段中,存在一段延迟。也就是说,getSnapshotBeforeUpdate计算的是当时的dom数据,而不是更新之后的dom数据。

componentDidCatch()

1
componentDidCatch(error, info)

错误边界是用来捕获子组件发生的错误,记录错误原因,并用UI显示。它优化了原先因为子组件异常而使整个组件树崩溃的不好体验。错误边界发生在子组件rendering阶段,生命周期阶段,整个组件树的构建阶段。
如果类组件定义了componentDidCatch这个方法,就表示这个组件会成为错误边界。在这个方法里调用setState可以将错误信息以界面的形式显示出来。componentDidCatch只能用来从异常中恢复,不要尝试将它用在控制流中,即不要将它控制我们的业务逻辑等。
想知道更多错误边界,可以看:Error Handling in React 16

注意:
错误边界只能捕获子组件产生的错误,无法捕获自身发生的错误。

待废弃方法

下面的方法虽然仍然有效,但是我们不推荐使用。你可以通过这篇文章自动更新你的组件。

UNSAFE_componentWillReceiveProps()

注意:
这个生命周期经常会导致bug,不一致问题。因此,React将在未来废除这个方法。如果因为props改变,你需要操作一个副作用(拉取数据或动画),推荐用componentDidUpdate方法替代。
其它情况,你可以参考:这篇文章
如果你需要用componentWillReceiveProps计算因props改变而造成的某些值改变的话,你可以用一些辅助函数
如果你想因为props改变,重置state,可以考虑将组件换成完全可控的,或者利用key属性。
在非常非常罕见的时候,你可能会用到getDerivedStateFromProps做为最后的方案。

UNSAFE_componentWillReceiveProps是已挂载的组件介绍到新的props的时候,才会被调用。如果因为props改变,你需要更新state,你需要将当前的props和nextProps对比,然后用setState。
如果因为父组件导致当前组件重新render,那么这个方法会被无条件调用。所以确定这里会有个比较。
React不会在未挂载阶段调用UNSAFE_componentWillReceiveProps。这个方法只会在props改变,和父组件重新render的时候调用。使用this.setState()通常并不会触发UNSAFE_componentWillReceiveProps。

UNSAFE_componentWillUpdate()

1
UNSAFE_componentWillUpdate(nextProps, nextState)

当组件接受到新的props或state,UNSAFE_componentWillUpdate会在render之前调用。第一次render之前,是不会触发这个函数的。
不要在这个函数里调用this.setState(),或者其他触发更新行为:dispatch redux action。
这个方法,可以被componentDidUpdate换种方式替换。如果你是想获取DOM信息的话,你可以考虑使用getSnapshotBeforeUpdate。

其它API

不像上节那些废弃的方法,下面的方法你可以在你的组件中调用:setState和forceUpdate。

setState()

1
setState(updater[, callback])

setState将组件状态的更新排列到队列中,并告知React这个组件,以及他的子组件都需要根据新的state重新render。基本上都是通过这个方法来更新界面的。
将setState设想成一个request,而不是立即更新的指令。为了优化性能,React会晚点执行它,这样就可以一下更新一些组件。React不会保证state会立即改变。
setState不会立即更新组件。通常都会被批量或延迟更新。这样就会导致我们经常在setState之后,立即执行this.state返回的还是原来的值。如果你不想这样,你可以使用componentDidUpdate或者用setState的callback来实现。这两个方法都能确保在state改变之后调用。如果你想基于原来的state去setState,可以重点看下updater参数。
setState都会触发render,除非shouldComponentUpdate返回的是false。
setState第一个参数是updater:

1
(state, props) => stateChange

state是对应用更改时组件状态的应用,不要直接修改state值。通过直接创建一个新对象表示这个改变。比如说,假设根据props.step增加value值:

1
2
3
this.setState((state, props) => {
return {counter: state.counter + props.step};
});

updater中的state和props,都能确保未来会被更新。updater输出的是和state的一个浅层合并
updater的第二个参数是可选的回调函数,这个回调函数是在setState完成,component重新render之后才会调用。通常情况下,我们会用componentDidUpdate替换这个方法。
同样,updater也接受object:

1
setState(stateChange[, callback])

这个会将stateChange浅层合并到state中,也就是说,他之后合并state.xxx,并不会合并state.xx.xxx之后的东东:

1
this.setState({quantity: 2})

这种方式的setState也是异步调用的。在同一个生命周期中,多次调用,会被批量处理。比如说,你想在一个生命周期中多次更行item.quantity:

1
2
3
4
5
6
Object.assign(
previousState,
{quantity: state.quantity + 1},
{quantity: state.quantity + 1},
...
)

在这个例子中,后续的调用将会覆盖先前的调用的值,所以quantity只会加1.如果下面一个state是依赖当前state,我们推荐使用function的模式:

1
2
3
this.setState((state) => {
return {quantity: state.quantity + 1};
});

更多信息,如下所示:

forceUpdate

1
component.forceUpdate(callback)

默认情况下,你的组件会在state、props改变的之后,自动render。但是,如果组件的render还依赖于别的数据,你可以使用这个方法。调用这个方法会跳过shouldComponentUpdate(想想也是合情合理),触发组件render。对于子组件来说,会走正常的生命周期流程,包括子组件中的shouldComponentUpdate。
正常情况下,尽量避免使用这个方法。

Class属性

defaultProps

defaultProps是定义在组件类上的。当属性是undefined的时候,才会用到defaultProps;null是不会的

1
2
3
4
5
6
7
class CustomButton extends React.Component {
// ...
}

CustomButton.defaultProps = {
color: 'blue'
};

如果props.color没有提供,这个就是’blue’。

1
2
3
render() {
return <CustomButton /> ; // props.color will be set to blue
}

但是props.color是null,color就会是null

1
2
3
render() {
return <CustomButton color={null} /> ; // props.color will remain null
}

displayName

displayName使用在debugging信息。通常情况下,你不需要设置他,因为他是根据function的名称或者class定义组件而来的。除非为了调试,你想设置一个不同的名称或者创建一个高阶组件时,你可以设置这个属性。详情可见:Wrap the Display Name for Easy Debugging

实例属性

props

this.props是在组件被调用的时候定义的。可以查看Components and Props获取更多信息。
this.props.children是比较特殊的属性。通常由JSX表达式中的子标签而不是标签本身定义。

state

state包含组件的数据,这些数据总会发生改变。state是用户定义的,他应该是plain JS object。什么plain Object,可以参考这段代码
如果某些值并不是用来render的,最好不要放在state中。这些值可以放在组件实例上。如:this._id。
阅读State and Lifecycle关注更多关于state的信息。
永远不要直接操作state,应该通过setState的方式。需要将this.state视为不可操作的对象。(PS:应该是为了前后对比,生命周期中,总用state, nextState)。

个人观点或问题

1. setState在constructor中使用会怎么样?

React会报warning:Can’t call setState on a component that is not yet mounted。如下:

set state in constructor


想想也是,setState设置组件render状态,在还未挂载的组件上setState,其实是不科学的,还不如直接对this.state赋值.

2. 重置组件状态

本人经常用的方法是利用生命周期:componentWillReceiveProps来重置组件状态。本文给出的方案是:直接改变组件的key值。哇塞~豁然开朗。超级棒~

3. getDerivedStateFromProps 和 componentWillReceiveProps有什么不同

getDerivedStateFromProps会在每次render都之前无条件触发。这个会与UNSAFE_componentWillReceiveProps形成对比,UNSAFE_componentWillReceiveProps只会在父组件render的时候才会被触发,并不会因为setState而触发。如果父组件重新render,子组件的UNSAFE_componentWillReceiveProps会被无条件调用。

4. In depth: When and why are setState() calls batched?

link: https://stackoverflow.com/questions/48563650/does-react-keep-the-order-for-state-updates/48610973#48610973

重点:不管你有多少个update,不管你发生在多少个组件里,只要在同一个事件里,都只会调用一次render
大体意思:在React16以及之前的版本,React会在一个event句柄里批量更行update。换而言之,在event之外,则立即更新。但是在React17版本,React将会默认批量更新,不管你是在event里面还是外面。
假设,ChildParent在click事件里都调用了setState,为了不要让Childrender两次,可行的方案是采用批量更新。
如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class H extends Component {
state = {
value: 1
};
onClick = value => {
this.setState({
value
});
}
render() {
return (
<div>
I am Parent, parentValue is {this.state.value}
<W onClick={this.onClick} />
</div>
);
}
}

class W extends Component {
state = {
value: 1
}
onClick = e => {
this.setState({
value: this.state.value + 1
});
this.props.onClick(this.state.value + 1);
}
render() {
return (
<div>
I am child, child value is {this.state.value}
<button onClick={this.onClick}>click me</button>
</div>
)
}
}

<W />点击按钮,子组件调用了自身方法,设置自身state的同时,调用了父组件的onClick方法,父组件设置父组件自身的state。如果是立即更新,<W />会调用两次render,显然,消耗性能。React采用批量更新,因为子组件、父组件在一个事件里,因此,子组件只调用了一次render。

那如何立即调用两次呢?很明显,将setState转成异步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class H extends Component {
state = {
value: 1
};
onClick = value => {
this.setState({
value
});
}
render() {
return (
<div>
I am Parent, parentValue is {this.state.value}
<W onClick={this.onClick} />
</div>
);
}
}

class W extends Component {
state = {
value: 1
}
onClick = e => {
Promise.resolve()
.then(() => {
const value = this.state.value + 1;
this.setState({
value
}); // re-render
console.log(this.state.value, value); // 永远是相等的。
this.props.onClick(value); // re-render by parent
});
}
render() {
return (
<div>
I am child, child value is {this.state.value}
<button onClick={this.onClick}>click me</button>
</div>
)
}
}

将事件里的setState异步出来,因为不在一个句柄,所以setState立即调用。此时我们会发现,在setState立即调用之后,直接调用this.state.value,我们会发现得到的是更新后的值。这个时候若还用之前的代码:

1
2
3
4
5
6
7
Promise.resolve()
.then(() => {
this.setState({
value: this.state.value + 1
}); // re-render
this.props.onClick(this.state.value + 1); // re-render by parent
});

我们会发现parentValue 永远会比childValue大1。如下:

setState立即更新


梳理下整个的调用流程:child setState -> child re-render -> console.log -> parent setState -> parent render -> child re-render。

那么如何将不在一个事件里的更新做批量处理呢?React提供了另外一个方法,这个方法在React16里,不属于安全方法,但是到了React17里会更新。ReactDOM.unstable_batchedUpdates

1
2
3
4
5
6
7
8
9
10
Promise.resolve()
.then(() => {
ReactDOM.unstable_batchedUpdates(() => {
this.setState({
value: this.state.value + 1
}); // doesn't re-render
this.props.onClick(this.state.value + 1); // doesn't re-render
});
// When we exit unstable_batchedUpdates, re-renders once
});

只有当我们退出ReactDOM.unstable_batchedUpdates之后,React才会调用一次render。其实,对于React事件内部,是被unstable_batchedUpdates包裹起来的。这就是为什么不管你有多少个update,不管你发生在多少个组件里,只要在同一个事件里,都只会调用一次render

Plain Object

来自http://api.jquery.com/Types/#PlainObject
像用花括号{}或new Oject()创建出来的对象,是plain object。已下几种不是:

  1. Function
  2. Array
  3. String
  4. Booleans
  5. Numbers
  6. NaN
  7. BOM