简体   繁体   English

为什么String.prototype的方法可用于字符串文字?

[英]Why are methods of String.prototype available to string literals?

This question has come out of another , which concerns the behaviour of console.dir with string literals. 这个问题来自另一个问题 ,它涉及使用字符串文字的console.dir的行为。 In particular, see the comments on my answer . 特别是,请参阅我的回答评论。

As we all know, String objects in JavaScript have a number of methods. 众所周知,JavaScript中的String对象有许多方法。 Those methods are defined on the String.prototype object. 这些方法在String.prototype对象上定义。 String.prototype.toUpperCase for example. 例如String.prototype.toUpperCase We can therefore do things like this: 因此我们可以这样做:

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 is doing some form of conversion/cast when you call a method of String.prototype on a string literal. 很明显,当您在字符串文字上调用String.prototype的方法时,JavaScript解释器正在进行某种形式的转换/转换。 However, I can't find any reference to this in the spec . 但是,我在规范中找不到任何对此的引用。

It makes sense, because otherwise you'd have to explicity cast every string literal to a String object before you could use any of the methods, and that would be quite annoying. 这是有道理的,因为否则你必须明确地将每个字符串文字强制转换为String对象,然后才能使用任何方法,这将非常烦人。

So my question is, where is this functionality described, and am I right in assuming the literal value is temporarily cast to an instance of String ? 所以我的问题是,这个功能在哪里描述,我是否正确假设文字值暂时转换为String的实例? Am I over-thinking this and missing something obvious? 我是否过度思考并忽略了一些明显的东西?

It's defined here: 它在这里定义:

The following [[Get]] internal method is used by GetValue when V is a property reference with a primitive base value. 当V是具有基本基值的属性引用时,GetValue使用以下[[Get]]内部方法。 It is called using base as its this value and with property P as its argument. 使用base作为其值并使用属性P作为其参数调用它。 The following steps are taken: 采取以下步骤:

  1. Let O be ToObject(base). 设O为ToObject(base)。
  2. Let desc be the result of calling the [[GetProperty]] internal method of O with property name P. 设desc是调用属性名为P的O的[[GetProperty]]内部方法的结果。
  3. If desc is undefined, return undefined. 如果未定义desc,则返回undefined。
  4. If IsDataDescriptor(desc) is true, return desc.[[Value]]. 如果IsDataDescriptor(desc)为true,则返回desc。[[Value]]。
  5. Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]]. 否则,IsAccessorDescriptor(desc)必须为true,所以让getter为desc。[[Get]]。
  6. If getter is undefined, return undefined. 如果未定义getter,则返回undefined。
  7. Return the result calling the [[Call]] internal method of getter providing base as the this value and providing no arguments. 返回调用getter提供base的[[Call]]内部方法的结果作为此值并且不提供参数。

NOTE The object that may be created in step 1 is not accessible outside of the above method. 注意在上述方法之外无法访问可能在步骤1中创建的对象。 An implementation might choose to avoid the actual creation of the object. 实现可能会选择避免实际创建对象。 The only situation where such an actual property access that uses this internal method can have visible effect is when it invokes an accessor function. 使用此内部方法的此类实际属性访问可以具有可见效果的唯一情况是它调用访问器函数时。

Source: http://es5.github.com/#x8.7.1 资料来源: http //es5.github.com/#x8.7.1

The primitive string value is coerced to an object in step 1. 在步骤1中将原始字符串值强制转换为对象。


Example 1 例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 : 这里,表达式str.toUpperCase是根据11.2.1属性访问器中定义的语义计算的:

  1. The identifier str is evaluated according to identifier resolution (see 10.2.2.1 GetIdentifierReference ). 标识符str根据标识符解析进行评估(参见10.2.2.1 GetIdentifierReference )。 The result is a reference whose base value is the environment record of the current lexical environment, and whose referenced name is "str" . 结果是一个引用,其基值是当前词法环境的环境记录,其引用名称为"str" This reference is the baseReference . 该引用是baseReference
  2. The baseValue is determined by executing GetValue(baseReference) . baseValue是通过执行GetValue(baseReference)确定的。 Since baseReference is not a property reference (its base value is not an object or a primitive value, but an environment record), the GetBindingValue() method is called in order to retrieve the value of the reference. 由于baseReference不是属性引用(其基值不是对象或原始值,而是环境记录),因此调用GetBindingValue()方法以检索引用的值。 This method returns the value of the local variable str , ie the primitive String value 'some string' . 此方法返回局部变量str的值,即原始String值'some string' This value is the baseValue . 该值是baseValue
  3. The propertyNameValue evaluates to the primitive String value 'toUpperCase' . propertyNameValue计算为原始String值'toUpperCase' (I've shortened this process a bit for the sake of simplicity.) (为简单起见,我稍微缩短了这个过程。)
  4. A new reference is created whose base value is baseValue and whose referenced name is propertyNameValue . 创建一个新引用,其基值为baseValue ,其引用名称为propertyNameValue

So, there are two references involved in this process: 因此,此过程涉及两个引用:

  • str (base value: the environment record, referenced name: 'str' ) str (基值:环境记录,引用名称: 'str'
  • str.toUpperCase (base value: 'some string' , referenced name: 'toUpperCase' ) str.toUpperCase (基值: 'some string' ,引用名称: 'toUpperCase'

Finally, the invocation operator () is executed on the latter reference. 最后,调用operator ()在后一个引用上执行。 The value of that reference is determined according to the semantics defined at the top of this answer. 该引用的值是根据本答案顶部定义的语义确定的。

Example 2 例2

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

Here, the expression 'some string'.toUpperCase is evaluated according to the same "Property Accessor" semantics as in example 1: 这里,表达式'some string'.toUpperCase是根据与示例1中相同的“Property Accessor”语义计算的:

  1. The string literal 'some string' obviously evaluates to the primitive String value 'some string' . 字符串文字'some string'显然计算为原​​始字符串值'some string' This is the baseReference . 这是baseReference (Don't let the name confuse you - this is a string value, not a reference.) (不要让名称混淆你 - 这是一个字符串值,而不是引用。)
  2. The baseValue is determined by executing GetValue(baseReference) . baseValue是通过执行GetValue(baseReference)确定的。 Since baseReference is not a reference, the method simply returns the argument value, ie baseValue = baseReference . 由于baseReference不是引用,因此该方法只返回参数值,即baseValue = baseReference

As you can see, just like in example 1, baseValue is the primitive String value 'some string' . 如您所见,就像在示例1中一样, baseValue是原始String值'some string' The steps 3 and 4 are equivalent to the steps 3 and 4 in example 1. 步骤3和4等同于示例1中的步骤3和4。

So, both the identifier reference str and the string literal 'some string' evaluate to the same value - the primitive String value 'some string' - and that value is used as the baseValue for the new reference which is then invoked with () . 因此,标识符引用str和字符串文字'some string'计算为相同的值 - 原始字符串值'some string' - 该值用作新引用的baseValue ,然后用()调用。 And since this reference has a primitive base value, the semantics defined at the beginning of my answer apply. 由于此引用具有原始基值,因此在我的答案开头定义的语义适用。

That's exactly what it's doing. 这正是它正在做的事情。

Javascript boxes primitive types as needed. JavaScript的boxes需要原始类型。

Here's some more information: 以下是一些更多信息:

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

Per the reference literals are converted to objects: 根据参考文字转换为对象:

String literals (denoted by double or single quotes) and strings returned from String calls in a non-constructor context (ie, without using the new keyword) are primitive strings. 字符串文字(用双引号或单引号表示)和从非构造函数上下文中的String调用返回的字符串(即,不使用new关键字)是原始字符串。 JavaScript automatically converts primitives and String objects, so that it's possible to use String object methods for primitive strings. JavaScript自动转换基元和String对象,因此可以对原始字符串使用String对象方法。

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 有一种叫做autoboxing(在对象中包装原语) http://princepthomas.blogspot.com/2011/07/auto-boxing-javascript-primitive-types.html


edit: sory for duplication of Mike Christensen link - I did not notice it. 编辑:索里重复迈克克里斯滕森链接 - 我没有注意到它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM