Why are String.prototype methods available for string literals?

This question came from another that deals with the behavior of console.dir with string literals. In particular, see Comments on my answer .

As we all know, String objects in JavaScript have a number of methods. These methods are defined in the String.prototype object. String.prototype.toUpperCase e.g. Therefore, we can do such things:

 var s = new String("hello"), s2 = s.toUpperCase(); //toUpperCase is a method on String.prototype 

However, we can also do this:

 var s = "hello", //s is a string literal, not an instance of String s2 = s.toUpperCase(); 

Clearly, the JavaScript interpreter does some form of conversion / cast when you call the String.prototype method in a string literal. However, I cannot find references to this in spec .

This makes sense, because otherwise you would need to explicate each string literal to a String object before you can use any of these methods, and that would be very frustrating.

So, my question is where this functionality is described, and do I correctly assume that the literal value is temporarily passed to the String instance? I changed my mind and missed something obvious?

+5
source share
4 answers

It is defined here:

The [[Get]] internal method is used by GetValue when V is a property with a primitive base value. It is called using both its value and the P property as an argument. The following steps are performed:

  • Let O be TOObject (base).
  • Let desc be the result of calling the [[GetProperty]] O internal method with property name P.
  • If desc is undefined, return undefined.
  • If IsDataDescriptor (desc) is true, return desc. [[Value]].
  • Otherwise, IsAccessorDescriptor (desc) must be true, so let getter be desc. [[Get]].
  • If getter is undefined, return undefined.
  • It returns a result that calls the get [[Call]] getter internal method, which provides the base, and does not provide any arguments.

NOTE The object that can be created in step 1 is not accessible outside the above method. An implementation may decide to avoid actually creating the object. The only situation where such actual access to a resource that uses this internal method can have a visible Effect is when it calls the access function.

Source: http://es5.github.com/#x8.7.1

The initial string value is forcibly bound to the object in step 1.


Example 1

 var str = 'some string'; str = str.toUpperCase(); 

Here, the expression str.toUpperCase is evaluated according to the semantics defined in 11.2.1 Property Accessors :

  • The str identifier is evaluated according to the resolution of the identifier (see 10.2.2.1 GetIdentifierReference ). The result is a link, the base value of which is a record of the environment of the current lexical environment, and the reference name is "str" . This link is a baseReference.
  • baseValue is determined by executing GetValue(baseReference) . Since baseReference is not a reference to a property (its base value is not an object or primitive value, but is an environment record), the GetBindingValue() method is called in order to get the value of the link. This method returns the value of the local variable str , that is, the primitive value String 'some string' . This is the value of baseValue.
  • The NameValue property evaluates the primitive value of String 'toUpperCase' . (I shortened this process a bit for the sake of simplicity.)
  • A new link is created, the base value of which is baseValue, and the reference name is the NameNalue property.

So, in this process there are two links:

  • str (base value: environment record, reference name: 'str' )
  • str.toUpperCase (base value: 'some string' , reference name: 'toUpperCase' )

Finally, the call statement () is executed at the last link. The value of this link is determined according to the semantics defined at the top of this answer.

Example 2

 var str = 'some string'.toUpperCase(); 

Here the expression 'some string'.toUpperCase is evaluated using the same semantics of' Property Accessor 'as in Example 1:

  • The string literal 'some string' obviously evaluates to the primitive value of String 'some string' . This is a baseReference. (Don't let the name confuse you - this is a string value, not a link.)
  • BaseValue is determined by executing GetValue(baseReference) . Since baseReference is not a reference, the method simply returns the value of the argument, i.e. baseValue = baseReference.

As you can see, as in Example 1, baseValue is the primitive value of String 'some string' . Steps 3 and 4 are equivalent to steps 3 and 4 in example 1.

So, both the str identifier reference and the string literal 'some string' are evaluated with the same value - the primitive value String 'some string' - and this value is used as baseValue for the new link, which is then called using () . And since this link has a primitive basic meaning, the semantics defined at the beginning of my answer apply.

+7
source

What he does.

Javascript boxes primitive types as needed.

Here is some more info:

http://princepthomas.blogspot.com/2011/07/auto-boxing-javascript-primitive-types.html

+2
source

Per reference literals are converted to objects:

String literals (indicated by double or single quotes) and strings returned from String calls in the context of a non-constructor (that is, without using a new keyword) are primitive strings. JavaScript automatically converts primitives and String objects so that you can use String Object Methods for primitive strings.

+1
source

You are almost right. There is something called autoboxing (wrapping primitives in objects) http://princepthomas.blogspot.com/2011/07/auto-boxing-javascript-primitive-types.html


edit: sory to duplicate Mike Christensen's link - I didn't notice that.

0
source

Source: https://habr.com/ru/post/904123/


All Articles