1

重複の可能性:
オブジェクトは空ですか?

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

次のモカテストを考えると

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'

...驚くべきことではありませんか?

4

1 に答える 1

14

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 を実行することもできますJSON.stringify(toUpdate) is '{}'
  4. loop:Object.keysの代わりに使用できます。ただし、どこでもサポートされているわけではありませんが、Node、最新の非 IE ブラウザー、および IE9+ で動作します。forObject.keys(toUpdate).length isnt 0keys
  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が単純なオブジェクトになるかどうかわからない場合。

于 2012-05-07T06:40:57.030 に答える