使用eval在javascript中导入名称空间

时间:2013-07-07 23:48:31

标签: javascript

我试图在javascript中将一个名称空间的内容转储到另一个名称空间中。我可以直接做到这一点的唯一方法如下:

var CHESSMEN = {

  Chariot: function(color) {
    return {
      color: color,
      abbreviation: 'R',
      type: 'Chariot'
    };
  },

  Horse: function(color) {
    return {
      color: color,
      abbreviation: 'H',
      type: 'Horse'
    };
  },

  Elephant: function(color) {
    return {
      color: color,
      abbreviation: 'E',
      type: 'Elephant'
    };
  },

  Advisor: function(color) {
    return {
      color: color,
      abbreviation: 'A',
      type: 'Advisor'
    };
  },

  General: function(color) {
    return {
      color: color,
      abbreviation: 'G',
      type: 'General'
    };
  },

  Cannon: function(color) {
    return {
      color: color,
      abbreviation: 'C',
      type: 'Cannon'
    };
  },

  Soldier: function(color) {
    return {
      color: color,
      abbreviation: 'S',
      type: 'Soldier'
    };
  }
}
Object.freeze(CHESSMEN)

function Game(board) {

  for (var piece in CHESSMEN) {
    eval('var ' + piece + ' = CHESSMEN.' + piece);
  }

  if (typeof(board) === 'undefined') {
    var board = {
      a1: new Chariot('red'),
      b1: new Horse('red'),
      c1: new Elephant('red'),
      d1: new Advisor('red'),
      e1: new General('red'),
      f1: new Advisor('red'),
      g1: new Elephant('red'),
      h1: new Horse('red'),
      i1: new Chariot('red'),
      b3: new Cannon('red'),
      h3: new Cannon('red'),
      a4: new Soldier('red'),
      c4: new Soldier('red'),
      e4: new Soldier('red'),
      g4: new Soldier('red'),
      i4: new Soldier('red'),
      a10: new Chariot('black'),
      b10: new Horse('black'),
      c10: new Elephant('black'),
      d10: new Advisor('black'),
      e10: new General('black'),
      f10: new Advisor('black'),
      g10: new Elephant('black'),
      h10: new Horse('black'),
      i10: new Chariot('black'),
      b8: new Cannon('black'),
      h8: new Cannon('black'),
      a7: new Soldier('black'),
      c7: new Soldier('black'),
      e7: new Soldier('black'),
      g7: new Soldier('black'),
      i7: new Soldier('black')
    };
  }

  // et cetera
}

这里我使用for in循环来迭代冻结对象的键,并使用eval将这些键及其关联值转储到Game构造函数的范围内。许多人告诉我不要使用eval,但我没有看到直接合并命名空间的另一种方法。这不安全吗?对于我来说,将西洋棋棋子构造函数称为CHESSMEN对象的属性会不会更好?

2 个答案:

答案 0 :(得分:2)

正如@zerkms指出的那样,你应该使用CHESSMEN.Chariot等来访问它们:

var board = {
  a1: new CHESSMAN.Chariot('red'),
  b1: new CHESSMAN.Horse('red'),
  c1: new CHESSMAN.Elephant('red'),
  //etc.

此外,如果您打算使用Chariot,您几乎肯定不希望您的new按照您的方式实施。你想要的模式是:

  Chariot: function(color) {
    this.color = color;
    this.abbreviation = 'R';
    this.type = 'Chariot'
  },

否则,当您调用new时,将返回的是您正在创建的对象文字,而不是您可能想要的Chariot实例。如果您真正需要的只是您要返回的值,那么您可以在不使用new的情况下编写代码:

var board = {
  a1: CHESSMAN.Chariot('red'),
  b1: CHESSMAN.Horse('red'),
  c1: CHESSMAN.Elephant('red'),
  //etc.

答案 1 :(得分:1)

这是可能的,但严重气馁,在严格模式下不可能。

with (CHESSMEN) {
    // Now CHESSMEN's properties are available without saying "CHESSMEN.whatever"
    console.log(Chariot === CHESSMEN.Chariot); // logs "true"
}

我重申:这是一个坏主意。很难说出任何标识符所指的内容,它可以运行得更慢,并且它不能向前兼容。有关详细信息,请参阅MDN

至于eval的安全性:如果稍后某些时候,您的代码会以CHESSMEN具有用户定义属性的方式更改,则攻击者可以将属性foo; doHorriblyEvilThing();命名为你的代码做了可怕的恶事。