如何使一个对象属性无法扩展、修改和删除?

之前在使用Angular 8 时,遇到过一个问题:

在路由中取出路由里的路径参数可以使用this.activatedRoute.snapshot中的queryParams属性,即路径中?号后面的参数。但当时的需求是取完之后要删除某个参数(id)的值,所以想当然地进行如下操作

const params = this.activatedRoute.snapshot.queryParams;
delete(params.id);

运行之后打印params发现并没有生效,参数id还是在路径上,并没有被删除。

查找Angular源码https://github.com/angular/angular, 发现有关new ActivatedRouteSnapshot()的地方代码是:

if (route.path === '**') {
      const params = segments.length > 0 ? last(segments)!.parameters : {};
      snapshot = new ActivatedRouteSnapshot(
          segments, params, Object.freeze({...this.urlTree.queryParams}), this.urlTree.fragment!,
          getData(route), getOutlet(route), route.component!, route,
          getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + segments.length,
          getResolve(route));
    } else {
      const result = match(rawSegment, route, segments);
      if (!result.matched) {
        return null;
      }
      consumedSegments = result.consumedSegments;
      rawSlicedSegments = segments.slice(result.lastChild);

      snapshot = new ActivatedRouteSnapshot(
          consumedSegments, result.parameters, Object.freeze({...this.urlTree.queryParams}),
          this.urlTree.fragment!, getData(route), getOutlet(route), route.component!, route,
          getSourceSegmentGroup(rawSegment),
          getPathIndexShift(rawSegment) + consumedSegments.length, getResolve(route));
    }
	
	
// 而ActivatedRouteSnapshot的constructor是
constructor(
      /** The URL segments matched by this route */
      public url: UrlSegment[],
      public params: Params,
      /** The query parameters shared by all the routes */
      public queryParams: Params,
      /** The URL fragment shared by all the routes */
      public fragment: string,
      /** The static and resolved data of this route */
      public data: Data,
      /** The outlet name of the route */
      public outlet: string,
      /** The component of the route */
      public component: Type<any>|string|null, routeConfig: Route|null, urlSegment: UrlSegmentGroup,
      lastPathIndex: number, resolve: ResolveData) {
    this.routeConfig = routeConfig;
    this._urlSegment = urlSegment;
    this._lastPathIndex = lastPathIndex;
    this._resolve = resolve;
  }

其中的constructor中的queryParams在上面new的时候传入的是Object.freeze({...this.urlTree.queryParams}), 这就很清楚了,是Object.freeze方法阻止了对参数的删除。

那么除了Object.freeze,还有哪些方法可以对对象的属性扩展、修改和删除做限制呢?

扩展性:阻止扩展-Object.preventExtensions()

可以修改+删除
通过Object.isExtensible()来查看一个对象是否具有扩展性

密封性:阻止删除+扩展-Object.seal()

不能修改已有属性的可枚举性、可配置性、可写性,但可能可以修改已有属性的值
通过Object.isSealed()来查看一个对象是否具有密封性

冻结性:阻止修改+删除+扩展-Object.freeze()

完全只读
通过Object.isFrozen()来查看一个对象是否具有冻结性
补充:上述可枚举性、可配置性、可写性,可通过Object.getOwnPropertyDescriptors()来获取:
let a = {test: 'hello', test2: 'world'};
//test: {value: "hello", writable: true, enumerable: true, configurable: true}
//test2: {value: "world", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptors(a));
  • value
    • 该属性的值(仅针对数据属性描述符有效)
  • writable
    • 当且仅当属性的值可以被改变时为true。(仅针对数据属性描述有效)
  • configurable
    • 当且仅当指定对象的属性描述可以被改变或者属性可被删除时,为true。
  • enumerable
    • 当且仅当指定对象的属性可以被枚举出时,为 true。
  • get
    • 获取该属性的访问器函数(getter)。如果没有访问器, 该值为undefined。(仅针对包含访问器或设置器的属性描述有效)
  • set
    • 获取该属性的设置器函数(setter)。 如果没有设置器, 该值为undefined。(仅针对包含访问器或设置器的属性描述有效)

以上就是有关给对象限制属性操作的方法。

标签: Angular, javascript

添加新评论

0%