如何设计一个数据字典

本文探讨了如何设计数据字典,避免由于遍历原型链导致的错误结果。通过创建无原型的对象来解决原型污染问题,但同时保持字典枚举的安全性。文章提出了一个安全的数据字典实现,考虑了特殊属性名可能带来的污染,并确保在各种环境下都能正常工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据字典在Javascript语言里面随处可见,对象本身就可以看成一个数据字典,通过给对象设置属性与方法,达到一个字典的目的。

var dict = new Dict();

obj.pro1 = "hello world!!!";
obj.pro2 = function () {
    console.log("I'am pro2");
};

先来看一个常见的数据字典的设计:


function Dict() {
}

Dict.prototype.count = function() {
    let n = 0;
    for(let k in this) {
        n++;
    };
    return n;
};

//
let dict = new Dict();
dict.paul = 3;
dict.lebron = 23;

dict.count() // 3  

为什么给设置了两个属性,通过count计算得出的结果是3呢?这里比较容易看出来,因为for in会遍历原型链上的可枚举的属性,例如上面的count方法。为了避免这种由于遍历原型链导致的错误结果,实现一个改进版本:

var dict = {};

dict.diwy = 3;
dict.love = 10;

let n = 0;
for(let k in dict) {
   n++;
}
console.log(n)  //2

通过这种改进虽然能够得出正确的结果,但是我们把这一切能够正常运行的希望寄托于Object.prototype原型没有受到污染。这种假设通常伴随一定的风险,如果和其他人协同开发产品,你不能保证其他人也和你一样遵循相应的规范。

了解到潜在的原型污染问题之后,可以想到的做法是,构造一个对象,不依赖于常规的原型对象:

function C() {}
C.prototype = null;

来测试一下:

var c = new C();
Object.getPropertyOf(c) === null;//false
Object.getPropertyOf(c) === Object.prototype; //true

遗憾的是c对象的原型依然是Object.prototypeES5提供了一个方法来创建一个没有原型的对象:

var dict = Object.create(null);
Object.getPropertyOf(dict) === null; // true

通过创建一个没有原型的对象,可以很好的规避原型污染问题。但是如果你既需要对象原型,又想保证字典枚举的安全性,那就得改造一些字典的设计。

使用hasOwnProperty来判断对象的实体属性,而不是原型熟悉。

var dict = {};
dict.name = 'lebron';
dict.hasOwnPropertyOf("name") //true;
dict.hasOwnPropertyOf("valueOf") //false
"valudeOf" in dict //true

为了避免设置hasOwnPropertyOf这样奇怪的属性,我们需要在任何安全的位置提取出hasOwnPropertyOf方法。

var hasOwnProperty = Object.prototype.hasOwnProperty;
//或者  
var hasOwnProperty = {}.hasOwnProperty;  

hasOwnProperty.call(dict, "name"); //true

一个安全的数据字典实现:


function Dict(elements) {
  this.elements = elements || {};
}

Dict.property.has = function(key) {
  return {}.hasOwnPropertyOf(key);
};

Dict.property.get = function(key) {
  return this.has(key) ? this.elements[key] : undefined;
};

Dict.property.set = function(key, value) {
  this.elements[key] = value;
};

Dict.property.remove = function(key) {
  delete this.elements[key];
};

在一些javascript环境中,特殊的属性名__proto__可能会导致自身的污染问题(修改对象的原型)。我们必须把它优化掉:

function Dict(elements) {
  this.elements = elements || {};
  this.specialPropValue = undefined;
  this.specialProp = "__proto__";
  this.hasSpecialProp = false;
}

Dict.prototype.has = function(key) {
  if(key === this.specialProp) {
    return this.hasSpecialProp;
  }
  return {}.hasOwnPropertyOf.call(this.elements, key);
};

Dict.prototype.get = function(key) {
  if(key === this.specialProp) {
    return this.specialProp;
  }
  return this.has(key) ? this.elements[key] : undefined;
};

Dict.prototype.set = function(key, value) {
  if(key === this.specialProp) {
    this.specialPropValue = value;
  }
  else {
    this.elements[key] = value;
  }
};

这样javascript环境是否处理__proto__属性,该实现均能保证是可工作的,以上也算是数据字典比较好的一个设计吧!。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值