From 50c81d5fe68096fec9e4c5ff6c6cee73cd07704e Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Wed, 25 Nov 2015 18:23:31 -0800 Subject: [PATCH] Make createClass 10-15% faster on complex specs --- src/isomorphic/classic/class/ReactClass.js | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/isomorphic/classic/class/ReactClass.js b/src/isomorphic/classic/class/ReactClass.js index c606d625c2..441f3484f1 100644 --- a/src/isomorphic/classic/class/ReactClass.js +++ b/src/isomorphic/classic/class/ReactClass.js @@ -414,7 +414,7 @@ function validateTypeDef(Constructor, typeDef, location) { } } -function validateMethodOverride(proto, name) { +function validateMethodOverride(isAlreadyDefined, name) { var specPolicy = ReactClassInterface.hasOwnProperty(name) ? ReactClassInterface[name] : null; @@ -431,7 +431,7 @@ function validateMethodOverride(proto, name) { } // Disallow defining methods more than once unless explicitly allowed. - if (proto.hasOwnProperty(name)) { + if (isAlreadyDefined) { invariant( specPolicy === SpecPolicy.DEFINE_MANY || specPolicy === SpecPolicy.DEFINE_MANY_MERGED, @@ -465,6 +465,7 @@ function mixSpecIntoComponent(Constructor, spec) { ); var proto = Constructor.prototype; + var autoBindPairs = proto.__reactAutoBindPairs; // By handling mixins before any other properties, we ensure the same // chaining order is applied to methods with DEFINE_MANY policy, whether @@ -484,7 +485,8 @@ function mixSpecIntoComponent(Constructor, spec) { } var property = spec[name]; - validateMethodOverride(proto, name); + var isAlreadyDefined = proto.hasOwnProperty(name); + validateMethodOverride(isAlreadyDefined, name); if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { RESERVED_SPEC_KEYS[name](Constructor, property); @@ -495,7 +497,6 @@ function mixSpecIntoComponent(Constructor, spec) { // 2. Overridden methods (that were mixed in). var isReactClassMethod = ReactClassInterface.hasOwnProperty(name); - var isAlreadyDefined = proto.hasOwnProperty(name); var isFunction = typeof property === 'function'; var shouldAutoBind = isFunction && @@ -504,10 +505,7 @@ function mixSpecIntoComponent(Constructor, spec) { spec.autobind !== false; if (shouldAutoBind) { - if (!proto.__reactAutoBindMap) { - proto.__reactAutoBindMap = {}; - } - proto.__reactAutoBindMap[name] = property; + autoBindPairs.push(name, property); proto[name] = property; } else { if (isAlreadyDefined) { @@ -700,14 +698,14 @@ function bindAutoBindMethod(component, method) { * @param {object} component Component whose method is going to be bound. */ function bindAutoBindMethods(component) { - for (var autoBindKey in component.__reactAutoBindMap) { - if (component.__reactAutoBindMap.hasOwnProperty(autoBindKey)) { - var method = component.__reactAutoBindMap[autoBindKey]; - component[autoBindKey] = bindAutoBindMethod( - component, - method - ); - } + var pairs = component.__reactAutoBindPairs; + for (var i = 0; i < pairs.length; i += 2) { + var autoBindKey = pairs[i]; + var method = pairs[i + 1]; + component[autoBindKey] = bindAutoBindMethod( + component, + method + ); } } @@ -812,7 +810,7 @@ var ReactClass = { } // Wire up auto-binding - if (this.__reactAutoBindMap) { + if (this.__reactAutoBindPairs.length) { bindAutoBindMethods(this); } @@ -846,6 +844,7 @@ var ReactClass = { }; Constructor.prototype = new ReactClassComponent(); Constructor.prototype.constructor = Constructor; + Constructor.prototype.__reactAutoBindPairs = []; injectedMixins.forEach( mixSpecIntoComponent.bind(null, Constructor)