Matthew Campbell
Matthew Campbell

Reputation: 1884

More efficient Javascript

Looking for another eye on making the following Javascript more efficient.

The following JSON is produced from a Resteasy service:

var testing = {
   "com:klistret:cmdb:ci:pojo:successful":true,
   "com:klistret:cmdb:ci:pojo:count":1,
   "com:klistret:cmdb:ci:pojo:elements":{
      "com:klistret:cmdb:ci:pojo:id":123,
      "com:klistret:cmdb:ci:pojo:name":"Mars",
      "com:klistret:cmdb:ci:pojo:type":{
        "com:klistret:cmdb:ci:pojo:id":1,
        "com:klistret:cmdb:ci:pojo:name":"Environment"
      },
      "com:klistret:cmdb:ci:pojo:configuration":{
        "@www:w3:org:2001:XMLSchemainstance:type":"Environment",
        "@Watermark":"past",
        "com:klistret:cmdb:ci:commons:Name":"Mars"
      }
    }
 };

Extended the Extjs JSONReader to handle key depths higher than 2 in the createAccessor method. Wondering if there is a way to make the code more efficient? The function below will be called like function(testing, "com:klistret:cmdb:ci:pojo:configuration.@Watermark") where the com:klistret:cmdb:ci:pojo:elements property is the root.

createAccessor : function(){
    var re = /[\[\.]/;

    return function(expr) {
        if(Ext.isEmpty(expr)){
            return Ext.emptyFn;
        }

        if(Ext.isFunction(expr)){
            return expr;
        }

        # THIS FUNCTION I WANT TO BE EFFICIENT
        return function(obj){
         while (String(expr).search(re) !== -1) {
 var i = String(expr).search(re);
 var key = expr.substring(0, i);

 if (obj.hasOwnProperty(key)) {
  obj = obj[key];
 }

 expr = expr.substring(i+1, expr.length);
}

            return obj[expr];
        };
    };
}()

Upvotes: 1

Views: 554

Answers (2)

wombleton
wombleton

Reputation: 8376

This is what I use. I only allow dot annotation, mind:

Ext.override(Ext.data.JsonReader, {
  createAccessor: function() {
    return function(expr) {
      if (Ext.isEmpty(expr)) {
        return Ext.emptyFn;
      } else if (Ext.isFunction(expr)) {
        return expr;
      } else {
        return function(obj) {
          var parts = (expr || '').split('.'),
              result = obj,
              part,
              match;
          while (parts.length > 0 && result) {
            part = parts.shift();
            match = part.match(/^(.+?)(\[(\d+)\])?$/);
            result = result[match[1]];
            if (result && match[3]) {
              result = result[match[3]];
            }
          }
          return result;
        }
      }
    };
  }()
});

Upvotes: 1

Victor Nicollet
Victor Nicollet

Reputation: 24577

A basic optimization would be to avoid scanning the string twice with search, which is pretty slow.

The best you could do is replace all the string scanning and substring extraction with a single call to expr.split('.'), which would support accessors of the form aaa.bbb.ccc.ddd and turn them into an array like ['aaa','bbb','ccc','ddd']. The other two characters you seem to support ([ and ]) wouldn't work.

Alternately, you could do an initial match for /[^\].[]+/g over your entire string and keep the matches to obtain a similar array, but this would possibly be slower than the previous solution.

Upvotes: 1

Related Questions