user1720624
user1720624

Reputation:

Get the object that calls a function belonging to one of its properties OR namespacing prototypes?

(Obviously I'm not sure what the title of this should be.)

I'd like to be able to modify the prototypes of native objects with minimal risk (because trust me; I have heard over and over again how it's a mortal javascript sin).

My train of thought goes something like this: I can greatly reduce the possibility of conflicts if I can add my custom functions to a single object on a prototype rather than directly adding them to the prototype itself.

If I have the code,

String.prototype.foo = function() {
    //do stuff
};

...obviously the keyword this references the string that called it. However, if I do something like,

String.prototype.foo = {};

String.prototype.foo.bar = function() {
    //do stuff
};

...the keyword this references the object foo.

If there some way to overcome this?

Upvotes: 0

Views: 40

Answers (2)

James M. Lay
James M. Lay

Reputation: 2470

Well, there's a couple of ways to do this, depending on how much work you want to put in. Using bind is the most straightforward way, but you have to define the string as a variable so you can pass a reference of it to bind:

String.prototype.foo = function() { console.log(this); }
String.prototype.foo.bar = function() { console.log(this); }

var g = "hi there";
g.foo()  // Yields g

g.foo.bar() // Yields String.prototype.foo()
g.foo.bar.bind(g)()  // Yields g again.

There may be another very hackish way to produce the desired result by creating getters and setters on String.prototype.foo so that String.prototype.foo.bar activates a function that returns a function bound to the instance that foo refers to. ??? Confusing.

What might be the best solution to reduce the possibility of conflicts, is to take advantage of prototypal inheritance and create your own sub prototype of the native String.

function MyString(string) {

    this.foo = function() { //whatever };

    this.foo.bar = (function() {}).bind(this);

    this.toString = function() { return string; } // because toString is not generic.
}

MyString.prototype = new String();

Here, you're creating your own "sub-prototype" of the String prototype. It inherits all the properties of the String prototype and adds its own, all without altering the native strings at all. BONUS: this.foo and this.foo.bar will both refer to your instance.

var instance = new MyString("hi");
instance.foo();     // this == instance
instance.foo.bar(); // this == instance
instance.replace("i", "e");  // returns "he"

This maybe wasn't the answer you were looking for, but hopefully it will at least be helpful.

Upvotes: 0

Graham
Graham

Reputation: 6562

The only way to overcome this would be to override the context using call:

String.prototype.foo.bar.call('hello'))

which works, but is pretty ridiculous.

You're better off (as you've already heard) avoiding modifying native prototypes, and instead having an object with your methods accepting the string as a parameter.

Upvotes: 1

Related Questions