简体   繁体   中英

Object literal with nested function as prototype of data Object

I'm creating a GAS Spreadsheets Service based app that reads/writes & updates a row of data. I have a key-value object that represents a row of data, like the example data provided in snippet.

Use case:

var exampleData = [{weekendVolume=5186270,midweekVolume=16405609}]; 
// tuple length 2 of two known values

function _DataRecordObject( exampleData ) {
  this._endOfWeek = new Date().endOfWeek();// Date.prototype method
}

var _DataRecordMethods = {

    weekEnding: function() { 
      return this._endOfWeek.formatDateString()
    },
    weekMonth: function() { 
      return this._endOfWeek.getMonthLabelShort() 
    },
    /* Processed volume */
    weekendVolume: function() { 
      return 'weekendVolume'
    },
    midweekVolume: function() { 
      return 'midweekVolume' 
    },
    totalVolumeProcessed: function() { 
      return _SumTotal( 
        this.weekendVolume(),
        this.midweekVolume()
        )
    }
  }

_DataRecordObject.prototype = _DataRecordMethods;

The new DataRecordObject is prototype of a Sheet object that provides other helpful properties. _SumTotal is a helper function.

My question:

When I call a new DataRecordObject with sheet range as argument, how do I update the exampleData object with the new properties such as totalVolumeProcessed ?

For example:

var foo = new _DataRecordObject( exampleData );
Console.log( foo ); 
//[{weekEnding='Aug-17',weekMonth=4,weekendVolume=5186270,midweekVolume=16405609,totalVolumeProcessed=21591879}]

I'd like the flexibility of using constructor-prototype inheritence, but using a boilerplate style template like Object-literals. My intuition suggests that I need to pass the data object keys when constructing a new dataRecordObject.

I'm a newcomer to JavaScript and have not yet gotten my head around inheritance, prototypes, and respective design-patterns. Factories and Modules, or perhaps Observers seem like appropriate patterns but my limited experience with JS is a limiting factor to solving my problem.

This might work for you.

1) Define the prototype as an object literal:

var methods = {

  sayName: function() {
     return "My name is " + this.name;
  },

  sayAge: function() {
    return "I am " +  this.age + " years old";

  }


};

2) You can either make the 'methods' variable global or define it inside the following function. The function creates a new object using 'methods' variable as a prototype and populates it with values from the 'data' argument.

function createNewObj (data) {

  var data = data || null;

  var result = Object.create(methods);

  for (var key in data) {

    if (data.hasOwnProperty(key)) {

      result[key] = data[key];

    }

  }

  return result;

}

3) Bringing things together

function test() {

  var data = {name: "John", age: "32"};

  var row = createNewObj(data);

  Logger.log(row.name); //logs 'John'
  Logger.log(row.age); //logs '32'
  Logger.log(row.sayName()); //logs 'My name is John'
  Logger.log(row.sayAge()); //logs 'I am 32 years old'
  Logger.log(Object.getPrototypeOf(row)); // returns contents of the 'methods' object literal
  Logger.log(row.hasOwnProperty("sayName"));  //logs 'false' because 'hasOwnProperty' doesn't go up the prototype chain
  Logger.log("sayName" in row); //logs 'true' because 'in' goes up the chain

}

I suggest you take a look at this blog post by Yehuda Katz that dives deeper into prototypes http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/ It has examples of much cleaner code that might be helpful.

I've found a solution, which expands on @Anton-Dementiev 's response. His suggestion to read the Yehudi Katz was also most helpful.

The create new object function, _DataRecordObject is where the solution lies..

function _DataRecordObject( RowDataObject ) {
  this._endOfWeek = new Date().endOfWeek();// Date.prototype method 

  var data = RowDataObject || null;
  var result = Object.create( _DataRecordMethods );

  for (var key in data) {
    if ( data.hasOwnProperty( key ) ) {
    // if value is present in the RowDataObject, 
    // then assign its value to the result 
      result[key] = data[key];
    } else {
    // if not, the value is a method function, 
    // which should be evaluated in that context,
    // and then return the method value as result
      var foo = Object.getPrototypeOf( result )[ key ];
      result[key] = foo.call( data );
    }
  }
  return result;
}
//simples

Since the methods are passed as property functions, they need to be called as functions in that context.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM