2

This is what I would like to do

var myObject = {
  prop: "872349827194721934798",
  calcProp: (this.prop.length % 3),
  method1: function () { return this.calcProp; },
  method2: function () { return this.calcProp - 1; }
}

However it returns an error "this.prop is undefined".

Below works:

var myObject = {
  prop: "872349827194721934798",
  calcProp: function () {this.prop.length % 3;},
  method1: function () { return this.calcProp(); },
  method2: function () ( return this.calcProp() - 1;}
}

Now the usage of calcProp is myObject.calcProp()' and I want the usage to bemyObject.calcProp`. I know this will work.

var myObject = {
  init: function () { this.calcProp = this.prop.length % 3; },
  prop: "872349827194721934798",
  calcProp: null,
  method1: function () { 
    this.init();
    return this.calcProp; 
  },
  method2: function () { 
    this.init();
    return this.calcProp - 1;
  }
}

Is there a way to implement calcProp where the usage is Object.calcprop. Without calling an init().

EDITED - Additional Requirement


Note: Should have added to my requirements that I would like to try to stay away from modifying the properties outside of the initial definition. I do not want to do the following;

var myObject = {
  prop: "872349827194721934798",
  method1: function () { return this.calcProp; },
  method2: function () { return this.calcProp - 1; }
};
myObject.calcProp = (myObject.prop.length % 3);

I would like to keep it all in the initial definition.

John Hartsock
  • 85,422
  • 23
  • 131
  • 146
  • possible duplicate of [Self-references in object literal declarations](http://stackoverflow.com/questions/4616202/self-references-in-object-literal-declarations) – Felix Kling Oct 21 '11 at 18:31
  • @FelixKling No this is not a duplicate because I do not want to create an init function. I like the solution that Daniel Earwicker provided. – John Hartsock Oct 21 '11 at 18:39
  • @JohnHartsock: your `I would like to try to stay away from modifying the properties outside the initial definition` is not possible. JS is a scripting language and cannot self reference as it is being defined. You can sort of do this after, but you don't seem to want that. – vol7ron Oct 21 '11 at 19:03
  • Actually I lied --- you can use `get`, see [my answer](http://stackoverflow.com/questions/7853523/javascript-creating-object-properties-using-existing-object-property/7854198#7854198) below – vol7ron Oct 21 '11 at 19:14

5 Answers5

3
var myObject = {
  prop: "872349827194721934798",
  method1: function () { return this.calcProp; },
  method2: function () { return this.calcProp - 1; };
};
myObject.calcProp = (myObject.prop.length % 3);

Or to allow this to be done inline, write a helper:

function alloc(init) {
    var o = {};
    init.call(o);
    return o;
}

You can now say:

var myObject = alloc(function() {
   this.prop = "872349827194721934798";
   this.calcProp = (this.prop.length % 3);
   this.method1 = function () { return this.calcProp; };
   this.method2 = function () { return this.calcProp - 1; };
});
Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
  • Should have added to my requirements that I would like to try to stay away from modifying the properties outside of the initial definition. – John Hartsock Oct 21 '11 at 18:21
  • See update: there is no way to use object initialisation syntax in the way you want to because it doesn't expose a name for the semi-constructed object. The `alloc` function I've added does the minimum to expose a name for a blank object and then call a function to set it up. – Daniel Earwicker Oct 21 '11 at 18:31
  • 1
    You can accomplish this without the `alloc` function by treating the anonymous function as a constructor: `var myObject = new function() { /* all the same */ };` [jsFiddle Example.](http://jsfiddle.net/yTLKH/) – user113716 Oct 21 '11 at 18:47
1
var myObject = {
  prop     : "872349827194721934798",
  get calcProp(){ return this.prop.length % 3; },
  method1  : function () { return this.calcProp; },
  method2  : function () { return this.calcProp - 1; }
};



Example use: console.log(myObject.calcProp);

Note: get was introduced in ECMAScript5/Harmony, so if the JS engines weren't updated on older browsers, it may not work in those cases. Refer to Daniel's solution for something a little more support in older browsers.

Community
  • 1
  • 1
vol7ron
  • 40,809
  • 21
  • 119
  • 172
  • NB this behaves very differently. If `prop` is modified, a plain `calcProp` value will not change. But if `calcProp` is a dynamic property defined by a getter, it will change when `prop` changes as it is recalculated on every access. – Daniel Earwicker Oct 21 '11 at 21:05
  • @DanielEarwicker: I think he wanted calcProp to be the result of a function, without using the parenthetical syntax. The above does as you described: [example](http://jsfiddle.net/vol7ron/M6d2X/) – vol7ron Oct 21 '11 at 22:05
0

You have to create the object before you can access its members.

var myObject = { 
  prop: "872349827194721934798", 
  method1: function () { return this.calcProp; }, 
  method2: function () { return this.calcProp - 1; } 
};
myObject.calcProp = myObject.prop.length % 3; 

In the context of your object literal expression, this refers to the expression's context - likely the window. You get an undefined error, because your current context contains no prop property. If the context had a member named prop, that value would be used:

var prop = [];
var myObject = {
  prop: "872349827194721934798",    
  calcProp: (this.prop.length % 3),    
  method1: function () { return this.calcProp; },    
  method2: function () { return this.calcProp - 1; }    
};
myObject.calcProp; // 0 (ie, [].length % 3)

Edit: You shouldn't need to access the property, just use the same value. Eg:

var myObject = {
  prop: "some literal string",
  calcProp: "some literal string".length % 3
};

or

var myObject = {
  prop: someVariable,
  calcProp: someVariable.length % 3
};

Or, here's another approach:

function SomeObj(prop) {
    this.prop = prop;
    this.calcProp = this.prop.length % 3;
}
SomeObj.prototype.method1 = function () { return this.calcProp; };
SomeObj.prototype.method2 = function () { return this.calcProp - 1; };

var myObject = new SomeObj("872349827194721934798");
gilly3
  • 87,962
  • 25
  • 144
  • 176
  • Should have added to my requirements that I would like to try to stay away from modifying the properties outside of the initial definition. – John Hartsock Oct 21 '11 at 18:21
  • @JohnHartsock - The property of the object does not exist until the object has been created. You can't access a property of an object that doesn't exist. See my edit for another approach that may get you closer to what you are looking for. – gilly3 Oct 21 '11 at 18:32
  • Daniel Earwicker has a very clever solution. – John Hartsock Oct 21 '11 at 18:33
0

You have no choice but to do initialization by parts

var obj = { prop: ... };
obj.calcProp = ...

You can use some tricks to still be able to write this inline though:

//the module pattern allows for inline statements
var fullObj =(function(){
    var obj = { prop: ... };
    obj.calcProp = ...
    return obj;
}());

//a constructor function gives you unlimited power:
function init(obj){
    obj.calcProp = ...
    return obj;
}
var something = init({
    prop: "123"
    ...
});
hugomg
  • 68,213
  • 24
  • 160
  • 246
  • Not sure I understand your second scenario...Why did you wrap the obj in stuff? – John Hartsock Oct 21 '11 at 18:22
  • It was just an example of a case where you need to put things inline in an expression instead of spread over multiple statements. (Removed it anyway) – hugomg Oct 21 '11 at 18:26
  • Not exactly what I was hoping for. – John Hartsock Oct 21 '11 at 18:29
  • The thing is *you can't get what you are hoping for*. The literal syntax doen't handle circular references so the best you can do is try to make the process of splitting things into multiple statements more pleasant (for example, the module pattern avoids creating any variables that will polute the outlying scope) – hugomg Oct 21 '11 at 18:33
  • Daniel Earwicker provided a very clever solution to keep my code together as I wanted. – John Hartsock Oct 21 '11 at 18:36
0

This is pretty much the same as the other answers:

 var propVal = "872349827194721934798";
    var myObject = {
      prop: propVal ,
      calcProp: (propVal.length % 3),
      method1: function () { return this.calcProp; },
      method2: function () { return this.calcProp - 1; }
    }
DefyGravity
  • 5,681
  • 5
  • 32
  • 47
  • Should have added to my requirements that I would like to try to stay away from modifying the properties outside of the initial definition. – John Hartsock Oct 21 '11 at 18:23