diff --git a/bind.js b/bind.js index 7b785fc..55ea2e8 100644 --- a/bind.js +++ b/bind.js @@ -20,23 +20,17 @@ function bind(target, targetPath, descriptor) { var sourcePath = descriptor["<-"] || descriptor["<->"] || ""; var twoWay = descriptor.twoWay = "<->" in descriptor; descriptor.sourcePath = sourcePath; - var value = descriptor.value; - var parameters = descriptor.parameters = descriptor.parameters || source; - var document = descriptor.document; - var components = descriptor.components; var trace = descriptor.trace; // TODO: consider the possibility that source and target have intrinsic // scope properties var sourceScope = descriptor.sourceScope = new Scope(source); - sourceScope.parameters = parameters; - sourceScope.document = document; - sourceScope.components = components; var targetScope = descriptor.targetScope = new Scope(target); - targetScope.parameters = parameters; - targetScope.document = document; - targetScope.components = components; + + sourceScope.parameters = targetScope.parameters = (descriptor.parameters = descriptor.parameters || source); + sourceScope.document = targetScope.document = descriptor.document; + sourceScope.components = targetScope.components = descriptor.components; // promote convert and revert from a converter object up to the descriptor if (descriptor.converter) { @@ -121,7 +115,6 @@ function bind(target, targetPath, descriptor) { cancelSourceToTarget(); cancelTargetToSource(); }; - } function bindOneWay( diff --git a/bindings.js b/bindings.js index 09f3912..0e99acc 100644 --- a/bindings.js +++ b/bindings.js @@ -1,11 +1,10 @@ -var Map = require("collections/map"); var bind = require("./bind"); var compute = require("./compute"); var observe = require("./observe"); var stringify = require("./stringify"); -var bindingsForObject = new Map(); +var bindingsForObject = {}; var owns = Object.prototype.hasOwnProperty; exports.count = 0; @@ -57,10 +56,7 @@ function defineBinding(object, name, descriptor, commonDescriptor) { exports.getBindings = getBindings; function getBindings(object) { - if (!bindingsForObject.has(object)) { - bindingsForObject.set(object, {}); - } - return bindingsForObject.get(object); + return object.__bindingDescriptors__ || (object.__bindingDescriptors__ = {}); } exports.getBinding = getBinding; @@ -91,7 +87,6 @@ function cancelBinding(object, name) { for (var name in bindings) { return; // if there are any remaining bindings, short-circuit } - bindingsForObject["delete"](object); } } diff --git a/compile-observer.js b/compile-observer.js index 08ecd6d..610a63d 100644 --- a/compile-observer.js +++ b/compile-observer.js @@ -93,11 +93,12 @@ var semantics = compile.semantics = { }; var compilers = semantics.compilers; -Object.keys(Operators).forEach(function (name) { +var operators = Object.keys(Operators); +for(var i=0, name;(name = operators[i]); i++) { if (!compilers[name]) { compilers[name] = Observers.makeOperatorObserverMaker(Operators[name]); } -}); +} // a special Hell for non-enumerable inheritance compilers.toString = Observers.makeOperatorObserverMaker(Operators.toString); diff --git a/expand.js b/expand.js index f65ab86..916b73e 100644 --- a/expand.js +++ b/expand.js @@ -1,7 +1,6 @@ var Set = require("collections/set"); var Map = require("collections/map"); -var Operators = require("./operators"); module.exports = expand; function expand(syntax, scope) { diff --git a/parse.js b/parse.js index c4dc469..0b60f24 100644 --- a/parse.js +++ b/parse.js @@ -2,7 +2,7 @@ require("collections/shim"); var grammar = require("./grammar"); -var memo = {}; // could be Dict +var memo = Object.create(null); // could be Dict module.exports = parse; function parse(text, options) { @@ -13,7 +13,7 @@ function parse(text, options) { return parse(text, options); }) }; - } else if (!options && Object.prototype.hasOwnProperty.call(memo, text)) { + } else if (!options && (text in memo)) { return memo[text]; } else { try { diff --git a/scope.js b/scope.js index f6c30ba..b7ce283 100644 --- a/scope.js +++ b/scope.js @@ -5,6 +5,18 @@ function Scope(value) { this.value = value; } +Object.defineProperties(Scope.prototype, { + parent: { + value:null, + writable: true + }, + value: { + value:null, + writable: true + } +}); + + Scope.prototype.nest = function (value) { var child = Object.create(this); child.value = value; diff --git a/spec/bind-defined-spec.js b/spec/bind-defined-spec.js index 2ecb779..00d9d03 100644 --- a/spec/bind-defined-spec.js +++ b/spec/bind-defined-spec.js @@ -11,10 +11,11 @@ describe("defined binding", function () { } }); expect(object.property).toBe(undefined); + expect(object.defined).toBeFalsy(); object.property = 10; expect(object.property).toBe(10); - expect(object.defined).toBe(true); + expect(object.defined).toBeTruthy(); object.defined = false; expect(object.property).toBe(undefined); diff --git a/spec/bind-reverse-spec.js b/spec/bind-reverse-spec.js new file mode 100644 index 0000000..2f54c50 --- /dev/null +++ b/spec/bind-reverse-spec.js @@ -0,0 +1,41 @@ +var Bindings = require(".."); + +describe("reverse binding", function () { + + it("should override initial value", function () { + var object = {foo: 42, bar: 0}; + Bindings.defineBinding(object, "foo", { "<->": "bar" }); + + expect(object.bar).toEqual(0); + expect(object.foo).toEqual(0); + }); + + it("should reflect first member change", function() { + var object = {foo: 42, bar: 0}; + Bindings.defineBinding(object, "foo", { "<->": "bar" }); + + object.foo = 123; + + expect(object.bar).toEqual(123); + expect(object.foo).toEqual(123); + }); + + it("should reflect second member change", function() { + var object = {foo: 42, bar: 0}; + Bindings.defineBinding(object, "foo", { "<->": "bar" }); + + object.bar = 123; + + expect(object.bar).toEqual(123); + expect(object.foo).toEqual(123); + }); + + it("should unset first member if second member is undefined", function() { + var object = {foo: 42}; + Bindings.defineBinding(object, "foo", { "<->": "bar", trace: true }); + + expect(object.bar).toBeUndefined(); + expect(object.foo).toBeUndefined(); + }); + +});