【问题标题】:What's the best way to built a JavaScript object so that it works AND passes JSLint?构建 JavaScript 对象以使其工作并通过 JSLint 的最佳方法是什么?
【发布时间】:2010-07-10 04:09:03
【问题描述】:

我一直在尝试查看是否可以尽可能直观地构建我的 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);
    }
  };
}

【问题讨论】:

  • 这与其说是一个答案,不如说是一个建议。不要太担心 jsLint。我经常觉得它太严格了。而是专注于编程。也就是说,我会让其他人讨论最佳实践。
  • 同意。我没有过分强调它。我只是根据我在互联网上在这里和那里学到的知识来构建我的代码。过去几天我一直在玩 JSLint,并有兴趣让其他人接受这一切。
  • 问题在于 init 和你的函数的顺序。在返回它将通过的对象之前移动 init。另外我认为你不需要函数 init。也许作为一个自动执行和匿名的 fn 只是为了分离事物。

标签: javascript jslint


【解决方案1】:

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);
    }
  };
}

【讨论】:

  • 如果我使用函数 setId() 定义我的函数没有区别,我在 JSLint 中得到相同的隐含全局错误。
  • 我刚刚通过 JSLint 运行它,它通过了。在他们的网站上试试。 jslint.com
  • setId 从不指代全局。由于提升,它总是引用局部变量。确实,这个局部变量的值最初是未定义的,但这无关紧要,因为它是在调用 init 时定义的。
  • 没有。所有变量声明都被提升到顶部。如果当前未将变量定义为保存函数,则无法调用该变量。但是,申报顺序无关紧要。而且我没有看到任何导致问题的递归场景。一个函数是封闭的,所以它可以调用自己..
  • @Matthew - 我的意思是就 JSLint 而言。我同意你的评估,但 JSLint 需要一个特定的订单。
【解决方案2】:

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

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

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

  }
}

它会警告 undefined,然后抛出 TypeError 错误。

【讨论】:

  • +1,我不知道吊装。我只是一直认为你必须按顺序声明。
  • 如果你想让它们跨浏览器工作,你必须按顺序声明它们。
  • @lawnsea,什么浏览器的行为不同,如何?
  • 噢!忽略我的评论。我没有对发生的事情给予足够的关注。
【解决方案3】:

我不了解 JSlint,但是在阅读了“javascript the good parts”之后,我总是将对象声明为字面量。

例如:

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 写的。

【讨论】:

  • 我拥有这本书。是的,这很好。我上面的示例使用闭包创建私有变量和函数,这也是 Crockford 在该书中提到的内容。在您的示例中,仅使用对象文字,我无法创建私有变量或函数。
  • 其实你是在声明一个对象。您正在声明一个对象,以及三个函数、两个布尔值和一个字符串,所有这些都填充到对象的属性中。
  • 另外,TrueFalse 在 JavaScript 中是小写的。
  • @icktoofay 是的,我知道我正在声明一个对象,我指的是 OP。不过,关于真/假,你是对的,我整天都在写 Python :-)
  • 要通过 JSlint,你可以这样写:/*jslint white: true */ (function () { 'use strict'; var Mogwai = { has_crazy_thoughts: true, reacts_to_water: true, name: 'Gizmo', eat:function(food){ return food; }, become_gremlin:function(){ return 2; }, cause_havoc:function(){ return 3; } }; Mogwai.eat({type: 'meat', when: 'after midnight'}); }());
【解决方案4】:

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

首先,您创建对象的方式似乎让人想起Module Pattern。据我记得,我链接到的文章是一本很好的读物。其次,也许您更喜欢与instantiate your objects 不同的方式。那篇文章给了你一个稍微不同的看法。

【讨论】:

  • 酷。现在阅读 Resig 的帖子。谢谢。
猜你喜欢
  • 2023-03-13
  • 2017-12-26
  • 1970-01-01
  • 2010-09-20
  • 2020-05-28
  • 1970-01-01
  • 2018-08-23
  • 1970-01-01
  • 2023-03-27
相关资源
最近更新 更多