JSX的本质

React.createElement

jsx 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖,

所有的jsx最终都会通过babel被转换成React.createElement的函数进行调用

Hello Wolrd

React.createElement('h2', { classname: 'foo' }, 'Hello World')

React.createElement的源码

// 存储一些特殊的react属性值
const RESERVED_PROPS = {
  key: true,
  ref: true,
  __self: true,
  __source: true,
}

// createElement的部分源码
export function createElement(type, config, children) {
  // ... 

  // props是实际存在内容的对象
  const props = {};

  // 属性不为null的时候,将属性依次挂载到props上
  if (config != null) {
    for (propName in config) {
      if (
        // 如果config自身有propName属性,且propName属性不是特殊的react属性的时候
        // 将该属性挂载到props上
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    }
  }

  // 从第三个参数开始就是子元素,使用arguments接收所有的实参
  // 并将所有的子元素挂载到props.children上
  // 也就是说子元素在传递的时候使用 React.createElement(type, config, child1, child2, child3, ...)
  const childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    // const childArray = Array(childrenLength); === const childArray = new Array(childrenLength);
    // 在使用Array构造器创建数组的时候,new关键字可以省略
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
  }

  // 调用ReactElement方法返回一个ReactElement对象,也就是vNode对象
  return ReactElement(
    type,
    props,
    // ...
  );
}

hasOwnProperty --- hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性

const obj = {name: 'Klaus'};
obj.__proto__.age = 23

// hasOwnProperty的参数为对应的属性名
console.log(obj.hasOwnProperty('name')) // => true
console.log(obj.hasOwnProperty('age')) // => false

// 注意: 如果hasOwnProperty方法的参数是一个没有定义的对象,那么脚本并不会报错,而是直接返回false
console.log(obj.hasOwnProperty(name)) // => false

ReactElement

通过 React.createElement方法 最终创建出来一个 ReactElement对象

而ReactElement对象的props.children属性中记录这当前元素的所有子元素

因此ReactElement本质就是vNode,其实也是vDom

React利用ReactElement对象组成了一个JavaScript的对象树,而这个JS对象树就是大名鼎鼎的虚拟DOM(Virtual DOM)

jsx

Hello Wolrd

Lorem ipsum dolor sit amet.

经过编译后,会形成如下vDom对象

1.png

React会将jsx编译为在内存中运行的vDOM,随后在通过ReactDOM.render将vDOM编译成对应的真实DOM

vdom的作用

1. 操作真实DOM性能较低

在JavaScript中,通过React.createElement创建出来的js对象是一个非常庞大的对象

并且DOM操作会引起浏览器的回流和重绘,所以频繁的DOM操作必然会导致性能的损失

而传统的开发模式不可避免的会需要进行频繁的DOM操作

而vDom本质就是一个js对象,这个对象是对真实DOM在内存中的抽象和模拟

vDom在结构上和真实DOM是一一映射的

而vDOM是存在于内存中的,且vDOM比真实DOM更为的轻量级,操作起来性能也更高

因为vDOM是在内存中运行的,我们可以将所有的更新在内存中统一进行修改后,一次性映射到真实DOM中

这样就避免了频繁的操作DOM,引起的重绘和回流

2.很难跟踪状态发生的改变

传统的开发中,跟踪界面中状态的改变是十分麻烦的,只能通过debugger和console

但是有了vDOM后,React DevTool就可以通过新旧vDOM的对比,进行页面状态的改变的跟踪

3.vDOM便于跨平台

UI在真正渲染之前会先被编译为vdom,

此时就可以根据不同的平台渲染成不同的内容

例如:

在web端,使用web端的ReactDOM.render,将VDOM渲染为真实DOM

在移动端,使用移动端的ReactDOM.render, 将VDOM渲染为原生控件( 如IOS的UIButton,Android的Button)

4 声明式编程

使用了vDOM后,UI以一种理想化或者说虚拟化的方式保存在内存中,并且它是一个相对简单的JavaScript对象

我们可以通过ReactDOM.render让 虚拟DOM 和 真实DOM同步起来,这个过程中叫做协调(Reconciliation)

因为大部分的DOM操作都交给React来帮助我们进行管理

所以这就意味着我们只需要维护和定义对应的状态即可,React会确保DOM和这些状态是匹配的

我们不需要直接进行DOM操作,可以从手动更改DOM、属性操作、事件处理中解放出来

阶段案例

  1. 以表格形式显示书籍数据
  2. 底部显示书籍总价
  3. 点击+或-可以更改数据数量,如果数量为1的时候,静止减少
  4. 点击移除按钮可以移除对应数据,如果全部移除,显示购物车为空
1.png



  
  
  
  Document
  
  
  
  


  

你可能感兴趣的:(JSX的本质)