1

With this script I add variables to an object on runtime :

function MyDocument(someDocument)
{
if(!(someDocument instanceof KnownDocumentClass))
    throw "Object must be an instance of KnownDocumentClass: " + someDocument;
this.Document = someDocument;
this.Fields = {};
this.updateValues = function()
    {
        for (var _it = this.Document.iterator(); _it.hasNext();) 
        {
            var _property = _it.next(); 
            try 
            {
                this[_property.getQualifiedName()] = _property.getContent();
            }
            catch(err)
            {
                log("Error :"+err);
            }
        }
    }
this.updateValues();

}

So, for example, I can use

var mydoc = new MyDocument(knownjavadoc);
log(mydoc.Creator) // Shows the original content.

This content could have multiple types (some are int, some Strings and a lot other custom java classes). So it can happen that log(mydoc.SomeProperty) returns :

PropertyObjectImpl[id=abc123, data=Some Data, type=Node, order=42]

I know, that I could add a function to MyDocument like

this.getValueAsString = function(name)
{
    var _prop = this[name];
    if(_prop instanceof PropertyObjectImpl)
       return "PropertyObject with ID : " + _prop.getID();
    else
       return _prop;
}

But for exercise purposes I want to add this function as toValueString() directly on these properties, so that a call like :

var value = mydoc.SomeProperty.toValueString()

instead of

var value = mydoc.getValueAsString("SomeProperty");

Is this possible?

Kooki
  • 1,157
  • 9
  • 30

2 Answers2

2

You can just override the .toString() implementation for the types in question, rather than implementing something which is likely going to do the same thing.

Overriding .toString() on existing types

Number.prototype.toString = function() {
    // return .toString() logic for Number types
}

Boolean.prototype.toString = function() {
    // return .toString() logic for Number types
}

Overriding .toString() on a custom type

var CustomType = (function() {
    function CustomType() {
        // CustomType logic
    }

    CustomType.prototype.toString = function() {
        // return .toString() logic for CustomType
    }

    return CustomType;
})();

Remember, toString() is built into the JavaScript specification for all objects, so you'd likely stick so convention overriding this, rather than implementing your own method. This is also less likely to break than implementing a custom method because .toString() should be callable from any property, whereas .toValueString() will only be callable on properties that implement it.

EDIT: If your method needs to return a completely custom string, for any type, then you need to ensure that you bind your custom method implementation to exiting types (Number, String, Boolean, Function, Object etc)

EDIT 2: As pointed out, overriding the default implementation of toString is considered bad practice, so another idea would be to bind your custom method at the Object level, so that it is callable from anything (since virtually everything in JavaScript extends Object)

Object.prototype.toValueString = function() {
    // return default implementation for this method;
}

CustomType.prototype.toValueString = function() {
    // return specific implementation for this method;
}
Matthew Layton
  • 39,871
  • 52
  • 185
  • 313
  • 2
    I would not advise redefining toString as its not good practive to touch objects you dont own (Think the PrototypeJs library that was out compared to something like jQuery). Standard / native objects should behave as expected. – pbo Feb 20 '14 at 12:04
  • Thanks for your answer, not an bad idea, but like pbo said, I don't want to override the default toString() of all those objects. – Kooki Feb 20 '14 at 12:25
1

I'm a bit confused to your question, but I'll give it a shot.

In JS, there is a standard interface for converting a value to a string: toString(). This is implemented on Object, which means all objects (and primitives casted to objects), will have the expected behavior.

var obj = {
    age: 25,
    customField: {
        name: "test",
        toString: function () { return this.name };
    }
};

obj.age.toString(); // "25"
obj.customField.toString() // "test"

As a side note, I would only capitalize variables/references that are function constructors (js classes). This is pretty much standard in the community.

pbo
  • 537
  • 4
  • 13
  • Thanks for your answer, but 'obj.customField.toString()' didn't work for me cause it returns the same creepy name like obj.customField ('PropertyObjectImpl[id=abc123, data=Some Data, type=Node, order=42]') and I have no influence on these object or his functions... – Kooki Feb 20 '14 at 12:23
  • Js is dynamic, can you extend these objects or simply set them with a toString method? – pbo Feb 20 '14 at 13:22
  • The other option is to wrap each of these object to adhere to whatever interface you need. Object.create(propertyObject) is one way where you will create a new object that inherits from his. Then with return append a toString – pbo Feb 20 '14 at 13:23