【问题标题】:Coffeescript isn't empty object [duplicate]Coffeescript 不是空对象[重复]
【发布时间】:2012-05-07 06:23:58
【问题描述】:

可能重复:
is object empty?

 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 {}

鉴于以下 Mocha 测试

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

结果是

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'

...令人惊讶,不是吗?

【问题讨论】:

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

标签: coffeescript


【解决方案1】:

CoffeeScript 的 is (AKA ==) 只是 JavaScript 的 ===isnt (AKA !=) 只是 JavaScript 的 !==。所以你的条件:

if toUpdate isnt {}

将始终为真,因为 toUpdate 和对象字面量 {} 永远不会是同一个对象。

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

EMPTY = {}

find: ->
    # ...
    EMPTY

及以后:

if toUpdate isnt EMPTY
    #...

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

a = { }
b = { }
console.log("a is b: #{a is b}")
console.log("a isnt b: #{a isnt b}")

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

a is b: false
a isnt b: true

但是这个:

class C
    EMPTY = { }
    find: -> EMPTY
    check: -> console.log("@find() == EMPTY: #{@find() == EMPTY}")

(new C).check()

会说:

@find() == EMPTY: true

演示:http://jsfiddle.net/ambiguous/7JGdq/

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

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

或者您可以使用上述特殊的EMTPY 常量方法。还有很多其他方法可以检查空对象,Ricardo Tomasi​ 提出了一些建议:

  1. Underscore 提供 _.isEmpty,它基本上是 for 循环方法,带有一些特殊情况处理和短路。
  2. 下划线还提供_.values,因此您可以查看_(toUpdate).values().length。这会在内部调用 map,如果可用,这将是本机 map 函数。
  3. 您甚至可以使用 JSON.stringify(toUpdate) is '{}' 来处理 JSON,这对我来说似乎有点脆弱,而且相当迂回。
  4. 您可以使用Object.keys 代替for 循环:Object.keys(toUpdate).length isnt 0keys 并非在所有地方都受支持,但它适用于 Node、最新的非 IE 浏览器和 IE9+。
  5. Sugar 也有Object.isEmpty,jQuery 也有$.isEmptyObject

短路for 循环似乎是检查空虚的最快方法:

(obj) ->
    for k of toUpdate
        return true
    false

假设您不需要own 来避免重复错误的事情。但鉴于这只是一个测试套件,而且空性测试几乎肯定不会成为您代码中的瓶颈,我会选择您拥有的 Underscore、Sugar 或 jQuery 中的任何一个(如果您需要可移植性并且必须处理通常的浏览器废话),Object.keys(x).length 如果您知道它将可用,(k for own k of toUpdate).length 如果您没有库并且必须处理浏览器废话并且不确定toUpdate 将是简单的对象。

【讨论】:

  • 所以它明确检查相同的引用,而不仅仅是相同的类型和值?检查空对象的惯用方法是什么……啊,玩得很好。这感觉几乎是邪恶的,但相当美味toUpdate.setProperty(key, value) for own key, value of data when ((k for own k of toUpdate).length isnt 0)
  • isEmpty()添加到Object.prototype会不会“坏掉”?我知道纯粹主义者对弄乱原型很挑剔,但不存在似乎真的很令人震惊。有理由不加吗?
  • @VisionarySoftwareSolutions:我不是一个纯粹主义者,但猴子修补核心对象对我来说很糟糕,尤其是对于像isEmpty 这样的通用名称。你可以抓住下划线并使用_(toUpdate).isEmpty(),无论如何,下划线都很方便。我认为toUpdate.setProperty(...) 的构造相当混乱,两个班轮会更好。
  • @muistooshort @VisionarySoftwareSolutions 如果您的环境支持Object.defineProperty,那么仔细扩展原生原型并没有错。
  • 其他几种检查方法,取决于支持:if JSON.stringify(obj) is '{}', if Object.keys(x).length
猜你喜欢
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 2014-10-11
  • 2017-06-28
  • 1970-01-01
  • 2013-06-12
  • 2012-11-25
相关资源
最近更新 更多