shapeFlag用于描述当前虚拟节点vnode的类型,在目前的实现代码中有两处需要用到shapeFlag进行判断
renderer.ts的patch方法中判断vnode是Element``Compnentrenderer.ts的mountElement方法中判断vnode的children类型是string还是array
正常实现
const shapeFlags = {
ELEMENT: 0,
STATEFUL_COMPONENT: 0,
TEXT_CHILDREN: 0,
ARRAY_CHILDREN: 0
}
以上根据vnode的类型和vnode.children的类型设置shapeFlags的property
// vnode 的类型是 element
shapeFlags.ELEMENT = 1
// vnode 的类型是 component
shapeFlags.COMPONENT = 1
// vnode.children 的类型是 string
shapeFlags.TEXT_CHILDREN = 1
// vnode.children 的类型是 array
shapeFlags.ARRAY_CHILDREN = 1
设置完shapeFlags的值之后,就可以这么判断
if(shapeFlags.ELEMENT) {
// vnode 的类型是 element 的情况需要进行的操作
...
}
if(shapeFlags.COMPONENT) {
// vnode 的类型是 component 的情况需要进行的操作
...
}
if(shapeFlags.TEXT_CHILDREN) {
// vnode.children 的类型是 string 的情况需要进行的操作
...
}
if(shapeFlags.TEXT_CHILDREN) {
// vnode.children 的类型是 array 的情况需要进行的操作
...
}
这样的实现代码可读性很高,很容易一眼就看出来什么情况下走什么判断
位运算实现
enum ShapeFlags {
ELEMENT = 1, // 0001
STATEFUL_COMPONENT = 1 << 1, // 0010
TEXT_CHILDREN = 1 << 2, // 0100
ARRAY_CHILDREN = 1 << 3, // 1000
}
// vnode 为 element 类型,vnode.children 为 string 类型
vnode.shapeFlag === 0101
// vnode 为 element 类型,vnode.children 为 array 类型
vnode.shapeFlag === 1001
// vnode 为 component 类型,vnode.children 为 string 类型
vnode.shapeFlag === 0110
// vnode 为 component 类型,vnode.children 为 array 类型
vnode.shapeFlag === 1010
根据上面的规则,实现代码
// vnode.ts
export function vnode(type, props?, children?) {
const vnode = {
...,
shapeFlag: getShapeFlage(type)
};
if (typeof children === "string") {
vnode.shapeFlag |= ShapeFlags.TEXT_CHILDREN;
} else if (Array.isArray(children)) {
vnode.shapeFlag |= ShapeFlags.ARRAY_CHILDREN;
}
return vnode;
}
function getShapeFlage(type) {
return typeof type === "string"
? ShapeFlags.ELEMENT
: ShapeFlags.STATEFUL_COMPONENT;
}
// renderer.ts
function patch(vnode, container) {
const { shapeFlag } = vnode;
if (shapeFlag & ShapeFlags.ELEMENT) {
processElement(vnode, container);
} else if (shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
processComponent(vnode, container);
}
}
function mountElement(vnode: any, container: any) {
const el = (vnode.el = document.createElement(vnode.type));
const { children, shapeFlag } = vnode;
if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
el.textContent = children;
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
mountChildren(vnode, el);
}
...
}
性能: 位运算实现 > 对象实现
代码可读性: 位运算实现 < 对象实现
我认为在实际的开发中,首先保证功能的实现,然后是代码的可读性,最后才从性能方面去进行代码优化