Coffeescript不是空物

Coffeescript isn't empty object

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
is object empty?

1
2
3
4
5
6
7
8
9
10
11
12
 update: (id, data) ->
    toUpdate = @find(id)
    if toUpdate isnt {}
            console.log"hi mom"
            console.log toUpdate
            toUpdate.setProperty(key, value) for own key, value of data

    return toUpdate

 find:(id) ->
    result = record for record in @storage when record.id is id
    return result or {}

考虑到以下摩卡测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
describe '#update', ->
    it 'should return an updated record from a given id and data when the record exists', ->
      boogie = createData()
      archive = new Archive("Dog")
      dog = archive.create(boogie)
      result = archive.update(1, {name:"Chompie", age:1})
      result.name.should.eql"Chompie"
      result.age.should.eql 1
      result.emotion.should.eql dog.emotion

    it 'should return an updated record from a given id and data when the record does not exist', ->
      boogie = createData()
      archive = new Archive("Dog")
      dog = archive.create(boogie)
      result = archive.update(50, {name:"Chompie", age:1})
      result.should.not.exist

结果是

1
2
3
4
5
6
7
8
9
10
11
12
Archive #update should return an updated record from a given id and data when the record exists: hi mom
{ id: 1,
  validationStrategies: {},
  name: 'Boogie',
  age: 2,
  emotion: 'happy' }
  ? Archive #update should return an updated record from a given id and data when the record exists: 1ms
    Archive #update should return empty when the record does not exist: hi mom
{}
    ? 1 of 13 tests failed:
    1) Archive #update should return empty when the record does not exist:
    TypeError: Object #<Object> has no method 'setProperty'

…令人惊讶,不是吗?

  • 注意,我最后为节点编写了一个简单的库来封装这个问题。如果您不想自己重复实现这一点(包括测试用例),请查看npmjs.org/package/emptyobject


coffeeesccript的is(aka ==)只是javascript的===isnt(aka !=只是javascript的!==。所以你的情况是:

1
if toUpdate isnt {}

因为toUpdate和对象文字{}永远不会是同一个对象,所以始终是正确的。

但是,如果@find可以返回一个常量中可用的已知"空"对象,那么可以使用isnt

1
2
3
4
5
EMPTY = {}

find: ->
    # ...
    EMPTY

稍后:

1
2
if toUpdate isnt EMPTY
    #...

例如,考虑这个简单的代码:

1
2
3
4
a = { }
b = { }
console.log("a is b: #{a is b}")
console.log("a isnt b: #{a isnt b}")

这将在您的控制台中提供:

1
2
a is b: false
a isnt b: true

但这是:

1
2
3
4
5
6
class C
    EMPTY = { }
    find: -> EMPTY
    check: -> console.log("@find() == EMPTY: #{@find() == EMPTY}")

(new C).check()

会说:

1
@find() == EMPTY: true

演示:http://jsfiddle.net/mizzy/7jgdq/

因此,您需要另一种方法来检查toUpdate是否为空。您可以计算toUpdate中的属性:

1
if (k for own k of toUpdate).length isnt 0

或者您可以使用上面概述的特殊EMTPY常量方法。还有其他各种方法可以检查空对象,Ricardo Tomasi?建议如下:

  • 下划线提供了_.isEmpty,基本上是for循环方法,具有一些特殊情况处理和短路。
  • 下划线还提供了_.values,因此您可以查看_(toUpdate).values().length。这在内部调用map,如果可用,它将是本地map函数。
  • 您甚至可以使用JSON.stringify(toUpdate) is '{}'通过JSON,这对我来说有点脆弱,而且还比较圆滑。
  • 您可以使用Object.keys而不是for循环:Object.keys(toUpdate).length isnt 0。虽然并非所有地方都支持keys,但它将与节点、最新的非IE浏览器和IE9+一起工作。
  • 糖也有Object.isEmpty,jquery有$.isEmptyObject
  • 短路for回路似乎是检查空虚的最快方法:

    1
    2
    3
    4
    (obj) ->
        for k of toUpdate
            return true
        false

    这假设您不需要own来避免重复错误的事情。但考虑到这只是一个测试套件,而且空虚测试在您的代码中几乎肯定不会成为瓶颈,我将使用您拥有的下划线、糖或jquery(如果您需要可移植性,并且必须处理通常的浏览器胡说八道)、Object.keys(x).length,如果您知道它将可用,以及(k for own k of toUpdate).length,如果您没有e库,必须处理浏览器的废话,不确定toUpdate是否是一个简单的对象。

    • 所以它显式地检查相同的引用,而不仅仅是相同的类型和值?检查空物体的惯用方法是什么……啊,玩得很好。这种感觉几乎是邪恶的,但相当美味。
    • isEmpty()添加到Object.prototype中会"中断"吗?我知道纯粹主义者会对弄乱原型大惊小怪,但似乎真的不存在。有没有理由不添加?
    • @视觉软件解决方案:我不是一个纯粹的人,但修补核心对象的猴子对我来说很难闻,特别是对于像isEmpty这样的通用名称。你只需抓取下划线并使用_(toUpdate).isEmpty(),下划线在任何情况下都非常方便。我认为toUpdate.setProperty(...)结构相当混乱,两行比较好。
    • @muistooshort@visionarysoftwaresolutions如果您所处的环境支持Object.defineProperty,那么小心地扩展本机原型没有任何问题。
    • @Ricardotomasi:我的主要问题是有可能出现冲突的猴子补丁,所以我避免使用它,除非我添加了一些应该存在的东西,或者我在名称前面加了前缀以避免冲突;不过,我想这其中有很多是仔细考虑的。defineProperty需要IE9+,不是吗?
    • 另外两种检查方法,取决于支持:if JSON.stringify(obj) is '{}'if Object.keys(x).length
    • @muistooshort是的,的确如此,但并不是每个人都在为浏览器(或所有浏览器)编码——这看起来像一个节点应用程序。
    • @Ricardotomasi:不过,keys有多便携?内联循环只是一个快速的、不脏的内联keys
    • 让我们在聊天中继续讨论
    • 实际上,我真的很感兴趣看到里卡多提出的代码片段的可移植性问题的结果,作为这个问题的其他"答案",记录下来留给子孙后代。你能加上对json.stringify()和object.keys(x).length的讨论吗?
    • @VisionarySoftwareSolutions:我根据与Ricardo的讨论添加了一些注释和选项。