0

How prototype property can be used with string variable in JavaScript. There is topic in our textbook which shows prototype as property but lack of explanations and confusing about it's usage

Take this code example for reference.

let x = 'stackoverflow';
console.log(x.prototype) // gives list of functions

console.log(x.prototype.toLowerCase())) // gives error
CrackerKSR
  • 1,380
  • 1
  • 11
  • 29
  • 1
    `String.prototype.charAt` is a function. You *could* call it as `String.prototype.charAt.call("abc", 2)`. – Thilo Nov 24 '19 at 10:21
  • 1
    Please look into how prototype chain works in javascript [Understanding prototypal inheritance in JavaScript](https://stackoverflow.com/questions/892595) and [How does JavaScript .prototype work?](https://stackoverflow.com/q/572897) and [What’s the purpose of prototype?](https://stackoverflow.com/questions/8433459) – adiga Nov 24 '19 at 10:23
  • 2
    Just a side note: `prototype` isn't a keyword. It's just the name of a property on most kinds of function objects. – T.J. Crowder Nov 24 '19 at 10:54

1 Answers1

2

The String.prototype object is what gives strings their methods (even though most strings you deal with are primitives, not objects). If there weren't a String.prototype.toLowerCase function, then "FOO".toLowerCase() wouldn't work. This is the fundamental prototypical nature of JavaScript (but a bit confusing, with most strings being primitives; more on that below¹).

One use of String.prototype in userland code is to add methods to strings:

Object.defineProperty(String.prototype, "initialCaps", {
    writable: true,
    configurable: true,
    value() {
        return this.charAt(0).toUpperCase() + this.slice(1);
    }
});


console.log("testing".initialCaps());

In general, extending built-in prototypes like that is best avoided in library or framework code because of the possibility of conflicts with other libraries, etc. It's generally okay in your own app or web page code, though.

A couple of best practices rules if you do that:

  • Make sure the methods you add are non-enumerable by using Object.defineProperty as in the example above. don't just do String.prototype.initialCaps = function() { /*...*/ };, that creates an enumerable property. Because the example above doesn't say enumerable: true, the property is non-enumerable by default. (Builtin methods are typically writable and configurable, though.)

  • Use names that are unlikely to be used by future additions to JavaScript, so they don't conflict later if things are added.

  • Never extend Object.prototype if you're using any third-party code. You may break that code.

  • Be cautious extending Array.prototype if you're using any third-party code. You may break that code.

With thorough testing you could of course go against any of those, but...


¹ About the primitive string vs. string object thing:

"example" creates a primitive string. Primitives aren't objects (in theory) and so they don't have properties or methods (in theory). But most primitives have an object constructor associated with them: String is the case of strings, Number for numbers, etc. (null and undefined do not have associated constructors.) If you try to use a property or method on a primitive with an associated constructor function, in theory the JavaScript engine creates an object equivalent of that primitive and then does the property/method lookup on that object. Since that object's prototype is the object from the prototype property on its constructor, it gets properties and methods from that object. If it's a method, the JavaScript engine calls the method with the original primitive value as this. (In loose mode, it'll get converted to object so this is an object within the call; in strict mode, though, this can be a primitive, and is in the case of method calls on a primitive.)

All of which is a long way of explaining that "example".toLowerCase() ends up calling String.prototype.toLowerCase with this set to "example".

I said "in theory" a couple of times above because JavaScript engines do a lot of optimization. As long as they behave in line with what the spec says, they don't have to literally do what the spec says. You can be fairly sure that when you do "example".length or "example".toLowerCase() (for instance), no modern JavaScript engine actually creates a String object under the covers for any of the built-in object properties/methods. (It may have to if you've added any, if your additions are in loose mode. One of many reasons to always use strict mode.)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    How does `String.prototype.length` work? It is not a function. Is it some sort of "abstract attribute" defined on the prototype that still does useful work when inherited by actual strings? – Thilo Nov 24 '19 at 10:24
  • 3
    @Thilo - `String.prototype.length` is a bit of an oddball, for mostly historic reasons. [`length`](https://tc39.es/ecma262/#sec-properties-of-string-instances-length) is a read-only data property of string *instances*. Although there is a `String.prototype.length`, it's not because it's a getter as you might expect (it isn't). The only reason `String.prototype.length` exists is that the [`String.prototype` object](https://tc39.es/ecma262/#sec-properties-of-the-string-prototype-object) itself is an "exotic String object" and it has a `length` data property whose value is `0`. – T.J. Crowder Nov 24 '19 at 10:34
  • 1
    (I should clarify that [*all* string objects are "exotic" objects](https://tc39.es/ecma262/#sec-string-exotic-objects), it's not just that the `String.prototype` object itself is.) – T.J. Crowder Nov 24 '19 at 11:03
  • @T.J.Crowder—weird, I hadn't looked that closely at strings before. It would be good if the spec said that strings were exotic objects in the sections on strings. MDN likely needs an update too, as it abscribes the behaviour of the instance *length* property to the [*String.prototype.length* property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length). – RobG Nov 24 '19 at 20:21
  • @RobG - Agreed, the only place I eventually found the statement *"String instances are String exotic objects..."* was [here](https://tc39.es/ecma262/#sec-properties-of-string-instances), which is a bit tucked away. I've updated MDN. – T.J. Crowder Nov 25 '19 at 07:58