5

I'm wondering why it seems that adding a method to the prototype of a string literal seems to work, but adding a property does not? I was playing with ideas in relation to this question, and have the following code:

String.prototype._str_index1 = 0;
String.prototype._str_reset = function() {
    this._str_index1 = 0;
};
String.prototype._str_substr = function(len) {
  var ret = this.substr(this._str_index1, len);
  this._str_index1 = this._str_index1 + len;
  return ret;
};

var testString = new String('Loremipsumdolorsitamet,consectetur');
log(testString._str_substr(5));
log(testString._str_substr(4));
​

This works fine. If however I change the third-last line to:

var testString = 'Loremipsumdolorsitamet,consectetur';

...it seems that although the method _str_substr exists and is callable on the string literal, the value of the property _str_index1 is always 0.

What's up?

Community
  • 1
  • 1
sje397
  • 41,293
  • 8
  • 87
  • 103
  • *Most* of the things you call ‘string literal’, are actually called ‘string primitive’: literals are a syntax to describe a string, e.g., to assign a string (or number, boolean, object, etc.) to a variable; primitive values are non-composite values that variables and objects can contain (apart from (other) objects). – Marcel Korpel Sep 21 '10 at 01:23
  • Except when it's not....'indexOf' is not a function when called against a string.... – Cris Stringfellow Nov 03 '12 at 07:48

2 Answers2

9

The string primitive is converted to a transient String object every time you try to invoke a method of the String object (the JavaScript engine internally converts a string primitive to a String object when necessary). After this function returns, the String object is (unobtrusively) converted back to a string primitive (under the hood) and this new primitive is returned (and most of the time assigned to a variable); every time a method of the String object is invoked.

So, after each invocation of testString._str_substr, _str_index1 is thrown away with the object and a new object (with a reset _str_index1) is created when _str_substr is called again.

See also MDC:

Because JavaScript automatically converts between string primitives and String objects, you can call any of the methods of the String object on a string primitive. JavaScript automatically converts the string primitive to a temporary String object, calls the method, then discards the temporary String object.

Marcel Korpel
  • 21,536
  • 6
  • 60
  • 80
2

This happens because the object is created and immediately thrown away when the assignment is made, because it's a string literal.

So with the first version, an object is created and kept, so testString is an object, not a string literal. In the second case, an object is created and thrown away, so all properties get lost...

Now try replacing that line with this:

var testString = 'Loremipsumdolorsitamet,consectetur'._str_substr();

Interesting, right? It still returns a string primitive, but that could be fixed...

String.prototype._str_substr = function(len) {
  var ret = this.substr(this._str_index1, len);
  this._str_index1 = this._str_index1 + len;
  return new String(ret);
};

Of course these are just suggestions designed to help explain why literals act differently than objects, not real-world recommendations...

Dagg Nabbit
  • 75,346
  • 19
  • 113
  • 141
  • No me neither. @no, I have no idea what you mean. – sje397 Sep 21 '10 at 00:49
  • “the object is created and immediately thrown away when the assignment is made” sounds like an object is created and thrown away on the *initial* assignment (`var testString = …`), not when invoking `_str_substr`. – Marcel Korpel Sep 21 '10 at 01:09
  • Hmm, I'm looking for it in the ECMAScript specification, but can't find it (at least not at this hour). But if that would be the case, the method of the `String` object can't be called after the string assignment is made. The string primitive has to be converted every time a method of the `String` object is invoked. – Marcel Korpel Sep 21 '10 at 01:41
  • Marcel: I think we're talking about the same thing... AFAIK a String object is temporarily created when a string is encountered and then thrown away. Maybe I'm wrong about that, the point was that it isn't an object from the time its declared, it's a primitive; stateless except for its value. When you call 'methods' of a string primitive it's just like applying String.prototype.x to the literal string. – Dagg Nabbit Sep 21 '10 at 01:52
  • You're correct (about that we're talking about the same thing). – Marcel Korpel Sep 21 '10 at 01:55