Coffeescript不是空物

Vis*_*ons 1 coffeescript

可能重复:
对象为空?

 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 {}
Run Code Online (Sandbox Code Playgroud)

鉴于以下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
Run Code Online (Sandbox Code Playgroud)

结果是

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'
Run Code Online (Sandbox Code Playgroud)

......很奇怪,不是吗?

mu *_*ort 14

CoffeeScript is(AKA ==)只是JavaScript,===isnt(AKA !=)只是JavaScript !==.所以你的情况:

if toUpdate isnt {}
Run Code Online (Sandbox Code Playgroud)

永远都是真的,因为toUpdate对象文字{}永远不会是同一个对象.

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

EMPTY = {}

find: ->
    # ...
    EMPTY
Run Code Online (Sandbox Code Playgroud)

然后:

if toUpdate isnt EMPTY
    #...
Run Code Online (Sandbox Code Playgroud)

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

a = { }
b = { }
console.log("a is b: #{a is b}")
console.log("a isnt b: #{a isnt b}")
Run Code Online (Sandbox Code Playgroud)

这会在你的控制台中给你这个:

a is b: false
a isnt b: true
Run Code Online (Sandbox Code Playgroud)

但是这个:

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

(new C).check()
Run Code Online (Sandbox Code Playgroud)

会说:

@find() == EMPTY: true
Run Code Online (Sandbox Code Playgroud)

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

所以你需要另一种方法来检查是否toUpdate为空.您可以计算以下属性toUpdate:

if (k for own k of toUpdate).length isnt 0
Run Code Online (Sandbox Code Playgroud)

或者您可以使用EMTPY上面概述的特殊常量方法.还有其他各种方法可以检查空物体,Ricardo Tomasi提出了一些建议:

  1. Underscore提供_.isEmpty的基本上是for循环方法,具有一些特殊的案例处理和短路.
  2. Underscore也提供,_.values所以你可以看看_(toUpdate).values().length.这在map内部调用,map如果可用,它将是本机函数.
  3. 你甚至可以使用JSON JSON.stringify(toUpdate) is '{}',这对我来说似乎有点脆弱而且相当圆润.
  4. 你可以使用Object.keys而不是for循环:Object.keys(toUpdate).length isnt 0.keys虽然它不受支持,但它可以与Node,最新的非IE浏览器和IE9 +一起使用.
  5. Sugar也有Object.isEmpty和jQuery一样$.isEmptyObject.

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

(obj) ->
    for k of toUpdate
        return true
    false
Run Code Online (Sandbox Code Playgroud)

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