React 源码中的 Object.seal

1,549 阅读2分钟

本文源码基于 React V16.8.6

源码

在 React 和 ReactROM 源码中,xx.development.js 代码都会使用到 Object.seal,主要是对 ref 做属性扩展限制,防止对象的 key 发生变更。

// createRef
export function createRef(): RefObject {
  const refObject = {
    current: null,
  };
  if (__DEV__) {
    Object.seal(refObject);
  }
  return refObject;
}
// useRef 相关
function mountRef<T>(initialValue: T): {current: T} {
  const hook = mountWorkInProgressHook();
  const ref = {current: initialValue};
  if (__DEV__) {
    Object.seal(ref);
  }
  hook.memoizedState = ref;
  return ref;
}

Object.seal

Object.seal() 方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要可写就可以改变。

图中,Object.seal 使用之前 configurable 是 true,使用之后变为 false。

这表示 Object.seal 处理后属性无法删除,也不能从数据描述变为存取描述MDN 属性描述符

更改枚举属性失败。

删除无效

不能把 a 从数据描述变为存取描述,但是可以通过 Object.defineProperty 改变它的 value,等同于 obj.a = '我是a'

如果对象被 Object.seal 处理过,则对象不能扩展和删除属性,尝试扩展一个属性

. 号方式扩展属性静默失败,用 Object.defineProperty 扩展则直接报错 Uncaught TypeError: Cannot define property c, object is not extensible,对象不可扩展了。

使用 Object.isSealed 判断对象是否被 Object.seal 处理。由于被处理的对象无法扩展属性,所以 Object.isExtensible(obj) 也是 false。

Object.freeze

Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。

Objct.freeze 是完全冻住了这个对象。不能对它和他内部做任何做更改。

使用 Object.defineProperty 更改 value 会直接报错。

obj.a = 10 也失败。

使用 Object.isFrozen(),判断是否被 freeze 了。

能否更改深层对象的属性

Object.seal 是可以更改第一层属性对应的值。

Object.freeze 是不能更改第一层属性对应的值,但可以更改更深层次的值!!!

obj1.a.name = 'yuny' 直接把 name 变成了 yuny


广告时间

欢迎关注,每日进步!!!