@autobind decorator.

This commit is contained in:
Julien Fontanet 2015-05-25 16:50:27 +02:00
parent a502965d19
commit 5c1611c484
2 changed files with 126 additions and 0 deletions

View File

@ -1,3 +1,57 @@
import bind from 'lodash.bind'
// ===================================================================
const {defineProperty} = Object
// ===================================================================
// See: https://github.com/jayphelps/core-decorators.js#autobind
export function autobind (target, key, {
configurable,
enumerable,
value: fn,
writable
}) {
return {
configurable,
enumerable,
get () {
const bounded = bind(fn, this)
defineProperty(this, key, {
configurable: true,
enumerable: false,
value: bounded,
writable: true
})
return bounded
},
set (newValue) {
if (this === target) {
// New value directly set on the prototype.
delete this[key]
this[key] = newValue
} else {
// New value set on a child object.
// Cannot use assignment because it will call the setter on
// the prototype.
defineProperty(this, key, {
configurable: true,
enumerable: true,
value: newValue,
writable: true
})
}
}
}
}
// -------------------------------------------------------------------
// Debounce decorator for methods.
//
// See: https://github.com/wycats/javascript-decorators

72
src/decorators.spec.js Normal file
View File

@ -0,0 +1,72 @@
/* eslint-env mocha */
import {expect} from 'chai'
// ===================================================================
import {autobind, debounce} from './decorators'
// ===================================================================
describe('autobind', function () {
class Foo {
@autobind
getFoo () {
return this
}
}
it('returns a bound instance for a method', function () {
const foo = new Foo()
const {getFoo} = foo
expect(getFoo()).to.equal(foo)
})
it('works with multiple instances of the same class', function () {
const foo1 = new Foo()
const foo2 = new Foo()
const {getFoo: getFoo1} = foo1
const {getFoo: getFoo2} = foo2
expect(getFoo1()).to.equal(foo1)
expect(getFoo2()).to.equal(foo2)
})
})
// -------------------------------------------------------------------
describe('debounce', function () {
let i
class Foo {
@debounce(1e1)
foo () {
++i
}
}
beforeEach(function () {
i = 0
})
it('works', function (done) {
const foo = new Foo()
expect(i).to.equal(0)
foo.foo()
expect(i).to.equal(1)
foo.foo()
expect(i).to.equal(1)
setTimeout(function () {
foo.foo()
expect(i).to.equal(2)
done()
}, 2e1)
})
})