5

我一直在尝试查看是否可以尽可能直观地构建我的 JavaScript 对象,同时确保它尽可能“正确”。我一直在通过 Crockford 的 JSLint.com 运行一堆不同的场景,但运气不佳。我似乎修复了一个错误,然后由于更改而弹出另一个错误。下面是我能得到的最好的。有人对此有其他看法吗?

这是我构造对象的典型方式:

function gizmo(id) {

  /* private variables */

  var myId = id;

  /* private methods */

  var init = function () {
    if (myId < 1) {
      setId(1);
    }
  };

  var setId = function (newId) {
    myId = newId;
  };

  // run 'constructor'
  init();

  /* public methods */

  return {
    getId: function () {
      return myId;
    },
    setId: function (newId) {
      setId(newId);
    },
    incrementId: function (inc) {
      setId(myId + inc);
    }
  };
}

// creating an instance of gizmo

var myGizmo = gizmo(-2);
console.log(myGizmo.getId()); // outputs 1

myGizmo.setId(5);
console.log(myGizmo.getId()); // outputs 5

myGizmo.incrementId(2);
console.log(myGizmo.getId()); /// outputs 7

这似乎运作良好。但是,当我通过 JSLint 运行它时,它给了我一个错误,指出我的两个私有函数是“隐含的全局函数”。

我能想到的最好的方法是在顶部使用如下变量声明我的函数:

function gizmo(id) {

  /* private variables */

  var myId = id,
      init,
      setId;

  /* private methods */

  init = function () {
    if (myId < 1) {
      setId(1);
    }
  };

  setId = function (newId) {
    myId = newId;
  };

  // run 'constructor'
  init();

  /* public methods */

  return {
    getId: function () {
      return myId;
    },
    setId: function (newId) {
      setId(newId);
    },
    incrementId: function (inc) {
      setId(myId + inc);
    }
  };
}
4

4 回答 4

3

JSLint 期望在 init 中引用 setId 之前定义它。

这通过了 JSLint。

function gizmo(id) {

  /* private variables */

  var myId = id;

  /* private methods */

  var setId = function (newId) {
    myId = newId;
  };

  var init = function () {
    if (myId < 1) {
      setId(1);
    }
  };

  // run 'constructor'
  init();

  /* public methods */

  return {
    getId: function () {
      return myId;
    },
    setId: function (newId) {
      setId(newId);
    },
    incrementId: function (inc) {
      setId(myId + inc);
    }
  };
}
于 2010-07-10T04:37:10.060 回答
1

我很确定这是 JSLint 中的一个错误。它还没有见过setId,所以它假设它是全球性的。但实际上,这并没有什么区别,因为根据ECMAScript 5 10.5var所有的 s 都被提升了。这意味着您的第一个示例和第二个示例在语义上是相同的。函数中任何地方的局部变量声明都会立即处理,并且绑定最初设置为具有值。但是当函数(例如 init)实际运行时,封闭值不再是.undefinedundefined

要查看它setId最初是未定义的,但从不引用全局,请执行以下测试:

function setId()
{
  alert("Global setId");
}
function f()
{
  var init = function()
  {
    setId();
  }
  alert(typeof(setId));
  init();
  var setId = function()
  {

  }
}

它将警告未定义,然后抛出TypeError错误。

于 2010-07-10T04:51:43.943 回答
0

我不了解 JSlint,但在阅读了“javascript 的优点”之后,我总是将对象声明为文字。

例如:

Mogwai={
  has_crazy_thoughts:True,
  reacts_to_water:True,
  name: 'Gizmo',
  eat:function(food){
    // code
  },
  become_gremlin:function(){
    // code
  },
  cause_havoc:function(){
    // code
  }
}

您实际上并没有在上面声明任何对象。只是一个功能。Javascript 中并不真正存在内部函数——它根本不像 Java。

编辑:我强烈推荐上面提到的书(无从属关系):http: //oreilly.com/catalog/9780596517748 ...它是由给我们带来 JSlint 的 Douglas Crockford 写的。

于 2010-07-10T04:26:55.280 回答
0

自从我认真地编写 JavaScript 以来已经有很长一段时间(几年),所以我对最佳实践细节的记忆已经完全消失了。我所做的是回去挖掘一些资源,可以帮助您做出明智的决定。

首先,您创建对象的方式似乎很容易让人联想到模块模式。据我记得,我链接到的文章是一本很好的读物。其次,也许您更喜欢用不同的方式来实例化您的对象。那篇文章给你一个稍微不同的看法。

于 2010-07-10T04:39:29.773 回答