Sfoglia il codice sorgente

return objects from expreesion parser, since attaching properties to functions is slower than using a wrapper object.

Evan You 11 anni fa
parent
commit
c2eee4ea39
3 ha cambiato i file con 39 aggiunte e 35 eliminazioni
  1. 9 9
      src/directive.js
  2. 21 17
      src/parse/expression.js
  3. 9 9
      test/unit/specs/expression_parser_spec.js

+ 9 - 9
src/directive.js

@@ -50,15 +50,14 @@ function Directive (type, el, vm, descriptor, definition) {
   this._initDef(definition)
   this._initDef(definition)
 
 
   if (this.expression && !this.isLiteral) {
   if (this.expression && !this.isLiteral) {
-    // TODO
-    // test for simple path vs. expression
-    this._getter = expParser.parse(this.expression, this.twoway)
-    this._setter = this._getter.setter
-
+    // parse expression
+    var res = expParser.parse(this.expression, this.twoway)
+    this._getter = res.get
+    this._setter = res.set
+    // init dependencies
+    this._initDeps(res.paths)
     // init filters
     // init filters
     this._initFilters()
     this._initFilters()
-    // init dependencies
-    this._initDeps()
     // init methods that need to be context-bound
     // init methods that need to be context-bound
     this._initBoundMethods()
     this._initBoundMethods()
     // update for the first time
     // update for the first time
@@ -143,11 +142,12 @@ p._initFilters = function () {
  * e.g. in "a && a.b", if `a` is not present at compilation,
  * e.g. in "a && a.b", if `a` is not present at compilation,
  * the directive will end up with no dependency at all and
  * the directive will end up with no dependency at all and
  * never gets updated.
  * never gets updated.
+ *
+ * @param {Array} paths
  */
  */
 
 
-p._initDeps = function () {
+p._initDeps = function (paths) {
   var self = this
   var self = this
-  var paths = this._getter.paths
   paths.forEach(function (path) {
   paths.forEach(function (path) {
     self._addDep(path)
     self._addDep(path)
   })
   })

+ 21 - 17
src/parse/expression.js

@@ -108,13 +108,15 @@ function compileExpFns (exp, needSet) {
     .replace(restoreRE, restore)
     .replace(restoreRE, restore)
   var getter = makeGetter(body)
   var getter = makeGetter(body)
   if (getter) {
   if (getter) {
-    getter.body = body
-    getter.paths = paths
-    if (needSet) {
-      getter.setter = makeSetter(body)
+    return {
+      get   : getter,
+      body  : body,
+      paths : paths,
+      set   : needSet
+        ? makeSetter(body)
+        : null
     }
     }
   }
   }
-  return getter
 }
 }
 
 
 /**
 /**
@@ -135,13 +137,15 @@ function compilePathFns (exp) {
     path = Path.parse(exp)
     path = Path.parse(exp)
     getter = path.get
     getter = path.get
   }
   }
-  // save root path segment
-  getter.paths = [exp.match(rootPathRE)[0]]
-  // always generate setter for simple paths
-  getter.setter = function (obj, val) {
-    Path.set(obj, path, val)
+  return {
+    get: getter,
+    // always generate setter for simple paths
+    set: function (obj, val) {
+      Path.set(obj, path, val)
+    },
+    // save root path segment
+    paths: [exp.match(rootPathRE)[0]]
   }
   }
-  return getter
 }
 }
 
 
 /**
 /**
@@ -190,9 +194,9 @@ function makeSetter (body) {
  * @param {Function} fn
  * @param {Function} fn
  */
  */
 
 
-function checkSetter (fn) {
-  if (!fn.setter) {
-    fn.setter = makeSetter(fn.body)
+function checkSetter (hit) {
+  if (!hit.set) {
+    fn.set = makeSetter(hit.body)
   }
   }
 }
 }
 
 
@@ -217,9 +221,9 @@ exports.parse = function (exp, needSet) {
   // we do a simple path check to optimize for that scenario.
   // we do a simple path check to optimize for that scenario.
   // the check fails valid paths with unusal whitespaces, but
   // the check fails valid paths with unusal whitespaces, but
   // that's too rare and we don't care.
   // that's too rare and we don't care.
-  var getter = pathTestRE.test(exp)
+  var res = pathTestRE.test(exp)
     ? compilePathFns(exp)
     ? compilePathFns(exp)
     : compileExpFns(exp, needSet)
     : compileExpFns(exp, needSet)
-  expressionCache.put(exp, getter)
-  return getter
+  expressionCache.put(exp, res)
+  return res
 }
 }

+ 9 - 9
test/unit/specs/expression_parser_spec.js

@@ -1,10 +1,10 @@
 var expParser = require('../../../src/parse/expression')
 var expParser = require('../../../src/parse/expression')
 
 
 function assertExp (testCase) {
 function assertExp (testCase) {
-  var fn = expParser.parse(testCase.exp)
-  expect(fn(testCase.scope)).toEqual(testCase.expected)
-  expect(fn.paths.length).toBe(testCase.paths.length)
-  fn.paths.forEach(function (p, i) {
+  var res = expParser.parse(testCase.exp)
+  expect(res.get(testCase.scope)).toEqual(testCase.expected)
+  expect(res.paths.length).toBe(testCase.paths.length)
+  res.paths.forEach(function (p, i) {
     expect(p).toBe(testCase.paths[i])
     expect(p).toBe(testCase.paths[i])
   })
   })
 }
 }
@@ -193,23 +193,23 @@ describe('Expression Parser', function () {
   })
   })
 
 
   it('dynamic setter', function () {
   it('dynamic setter', function () {
-    var setter = expParser.parse('a[b]', true).setter
+    var res = expParser.parse('a[b]', true)
     var scope = {
     var scope = {
       a: { c: 1 },
       a: { c: 1 },
       b: 'c'
       b: 'c'
     }
     }
-    setter(scope, 2)
+    res.set(scope, 2)
     expect(scope.a.c).toBe(2)
     expect(scope.a.c).toBe(2)
   })
   })
 
 
   it('simple path setter', function () {
   it('simple path setter', function () {
-    var setter = expParser.parse('a.b.c', true).setter
+    var res = expParser.parse('a.b.c', true)
     var scope = {}
     var scope = {}
     expect(function () {
     expect(function () {
-      setter(scope, 123)
+      res.set(scope, 123)
     }).not.toThrow()
     }).not.toThrow()
     scope.a = {b:{c:0}}
     scope.a = {b:{c:0}}
-    setter(scope, 123)
+    res.set(scope, 123)
     expect(scope.a.b.c).toBe(123)
     expect(scope.a.b.c).toBe(123)
   })
   })