如何设计一个数据字典

数据字典在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__属性,该实现均能保证是可工作的,以上也算是数据字典比较好的一个设计吧!。

你可能感兴趣的:(JavascriptDP)