前端怎样定义一个常量

许多编程言语供应了const症结词声明一个常量,在ES6中也是供应了const,然则在前端的const与其他编程言语差别,其并不意味着声明的变量就是一个常量。运用const b = {}声清楚明了一个常量b,然则经由过程运用b.a = 1去修正对象b却并没有报错,我们修正了一个底本以为是常量现实上是变量的对象。

为何会如许?

现实上,const定义的变量保留的是指向现实数据的指针,关于基础数据类型String、Boolean、Number、undefined、null、Symbol而言,
其值保留在栈内存中的简朴数据段,按值接见,就是等同于常量。然则相干于援用数据类型而言,const只能保证指向保留在堆内存中的对象的指针坚持稳定,换句话说
const能够保证变量一直指向同一个对象,至于对象的修正无计可施。

所以,在前端中究竟怎样完成一个常量!

Object.freeze

Object.freeze能够凝结对象,不能新增和删除属性,同时对象已有属性都是不可枚举、不可设置、不可写。须要注重的是运用该要领只能让对象浅凝结,其内部属性为对象时
照旧能够被改动,要想完成完全凝结,那末就须要举行以下操纵。

function deepConst(data){
  Object.freeze(data);
  for(let key in data){
    let prop = data[key];
    if(!data.hasOwnProperty(key) || !(typeof prop === "object") || Object.isFrozen(prop)){
      continue;
    }
    deepConst(prop);
  }
}

Object.defineProperty、Object.preventExtensions、Object.seal

Object.preventExtensions

该要领能够将对象变成不可扩大即对象即不能增加新的属性,然则对象的原有属性照旧能够被删除或修正,同时假如属性的值为对象,只管设置了
不能被增加属性,然则其属性值为对象的属性照旧能够增加属性。

举个例子:

let obj = {a:1,b:2,c:{d:3}};
Object.preventExtensions(obj);
obj.d = 1;
obj.a = 2;
delete obj.b;
obj.c.e = 10;
//输出{a:1,c:{d:3,e:10}
console.log(obj);

Object.seal

Object.preventExtensions比拟,该要领一样能够将对象变成不能增加新属性,而且该要领制止删除对象的属性。一样假如属性的值为对象,
属性值照旧能够增加新属性或删除属性。

举个例子

let obj = {a:1,b:2,c:{d:3}};
Object.seal(obj);
obj.e = 10;
delete obj.a;
delete obj.c.d;
obj.c.f = 10;
//输出{a:1,b:2,c:{f:10}
console.log(obj);

Object.defineProperty

Object.defineProperty(obj, prop, descriptor)在MVVM中大放异彩,运用其也能够将将对象完全凝结。在写代码之前我们
先相识下writable、Configurable须要晓得都内容,这才是此次凝结的症结。

writable

对象属性的值是不是能够被重写,为true示意许可,为false即被制止,默以为false。假如属性的值为对象,
只管设置了不能被重写,其属性为对象的值照旧能够被重写。

举个例子:

let obj = {a:1,b:2,c:{d:3}};
Object.defineProperty(obj,"a",{writable:true});
Object.defineProperty(obj,"b",{writable:false});
Object.defineProperty(obj,"c",{writable:false});
Object.defineProperty(obj,"e",{writable:false});
obj.a = 2;
obj.b = 3;
obj.c.d = 4;
//输出为2,即a属性的值被重写了
console.log(obj.a);
//输出照旧为2,即b属性的值没有被重写
console.log(obj.b);
//输出照旧为{d:4},假如属性的值为对象,只管设置了不能被重写,其属性为对象的值照旧能够被重写。
console.log(obj.c);
Configurable

configurable特征示意对象的属性是不是能够被删除,以及除writable特征外的其他特征是不是能够被修正。为true示意许可被修正
false示意制止修正,默以为false,假如属性的值为对象,只管设置了属性不能被修正,其属性为对象的属性照旧能够被修正。
举个例子

let obj = {a:1,b:2,c:{d:3}};
Object.defineProperty(obj,"a",{configurable:true});
Object.defineProperty(obj,"b",{configurable:false});
Object.defineProperty(obj,"c",{configurable:false});
delete obj.a;
delete obj.b;
delete obj.c;
//输出 {b:2,c:{}},假如属性的值为对象,只管设置了属性不能被修正,其属性为对象的属性照旧能够被修正。
console.log(obj);

上面这三个要领零丁拿出来并不能够圆满的将对象变成一个常量,然则我们组合一下就能够天生一个常量。

function deepConst(data){
  if (!data || typeof data !== 'object') {
    return;
  }
  //Object.preventExtensions(data);也能够完成
  Object.seal(data);
  Object.keys(data).forEach(function(key) {
    unWriteConfig(data, key, data[key]);
  });
}
function unWriteConfig(data, key, val) {
  deepConst(val);
  Object.defineProperty(data, key, {
    writable:false,
    configurable:false
  });
}

Proxy

Proxy在目的对象之前举行了一层阻拦,外界对对象的接见和修正都须要经由过程这层阻拦,所以我们能够操控阻拦来掌握对对象对接见和修正。Proxy
支撑的阻拦操纵浩瀚,下面只枚举与文章相干的操纵,假如想更深入相识Proxy,请看这篇文章

function createDeepProxy(target) {
  function makeHandler() {
    return {
      set(target, key, value, receiver) {
        return false;
      },
      deleteProperty(target, key) {
        return false;
      }
    }
  }
  
  function proxify(obj, path) {
    for(let key of Object.keys(obj)) {
      if(typeof obj[key] === 'object') {
        obj[key] = proxify(obj[key], [...path, key]);
      }
    }
    let p = new Proxy(obj, makeHandler());
    return p;
  }
  return proxify(target, []);
}
    原文作者:西瓜1994
    原文地址: https://segmentfault.com/a/1190000018509445
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞