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

时间:2011-12-20 20:57:26

标签: javascript

此问题来自another,它涉及console.dir与字符串文字的行为。特别是,请参阅my answer上的评论。

众所周知,JavaScript中的String个对象有很多方法。这些方法在String.prototype对象上定义。例如String.prototype.toUpperCase。因此,我们可以这样做:

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

但是,我们也可以这样做:

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

显然,当您在字符串文字上调用String.prototype的方法时,JavaScript解释器正在进行某种形式的转换/转换。但是,我无法在spec中找到对此的任何引用。

这是有道理的,因为否则你必须明确地将每个字符串文字强制转换为String对象,然后才能使用任何方法,这会非常烦人。

所以我的问题是,这个功能在哪里描述,我是否正确假设文字值暂时转换为String的实例?我是否过度思考并忽略了一些明显的东西?

4 个答案:

答案 0 :(得分:8)

这里定义:

  

当V为a时,GetValue使用以下[[Get]]内部方法   具有原始基值的属性引用。它被称为使用   base作为此值,属性P作为其参数。该   采取以下步骤:

     
      
  1. 设O为ToObject(base)。
  2.   
  3. 设desc是调用属性名为P的O的[[GetProperty]]内部方法的结果。
  4.   
  5. 如果未定义desc,则返回undefined。
  6.   
  7. 如果IsDataDescriptor(desc)为true,则返回desc。[[Value]]。
  8.   
  9. 否则,IsAccessorDescriptor(desc)必须为true,所以让getter为desc。[[Get]]。
  10.   
  11. 如果未定义getter,则返回undefined。
  12.   
  13. 返回调用getter提供base的[[Call]]内部方法的结果作为此值并且不提供任何参数。
  14.         

    注意无法访问步骤1中可能创建的对象   在上述方法之外。实现可能会选择避免   实际创建的对象。这样的唯一情况   使用此内部方法的实际属性访问可以显示   效果是它调用访问器函数。

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

在步骤1中将原始字符串值强制转换为对象。


示例1

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

这里,表达式str.toUpperCase是根据11.2.1 Property Accessors中定义的语义进行评估的:

  1. 根据标识符解析度评估标识符str(请参阅10.2.2.1 GetIdentifierReference)。结果是一个引用,其基值是当前词法环境的环境记录,其引用名称为"str"。此引用是 baseReference
  2. baseValue 是通过执行GetValue(baseReference)确定的。由于 baseReference 不是属性引用(其基值不是对象或原始值,而是环境记录),因此调用GetBindingValue()方法以检索值的参考。此方法返回局部变量str的值,即原始字符串值'some string'。该值为 baseValue
  3. propertyNameValue 计算为原始字符串值'toUpperCase'。 (为简单起见,我稍微缩短了这个过程。)
  4. 创建一个新引用,其基值为 baseValue ,其引用名称为 propertyNameValue
  5. 因此,此过程涉及两个参考:

    • str(基值:环境记录,引用名称:'str'
    • str.toUpperCase(基值:'some string',引用名称:'toUpperCase'

    最后,在后一个引用上执行调用操作符()。该引用的值是根据本答案顶部定义的语义确定的。

    示例2

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

    这里,表达式'some string'.toUpperCase根据与示例1中相同的“Property Accessor”语义进行评估:

    1. 字符串文字'some string'显然评估为原始字符串值'some string'。这是 baseReference 。 (不要让名称混淆你 - 这是一个字符串值,而不是引用。)
    2. baseValue 是通过执行GetValue(baseReference)确定的。由于 baseReference 不是引用,因此该方法只返回参数值,即 baseValue = baseReference
    3. 如您所见,就像示例1中一样, baseValue 是原始字符串值'some string'。步骤3和4等同于示例1中的步骤3和4。

      因此,标识符引用str和字符串文字'some string'都计算为相同的值 - 原始字符串值'some string' - 并且该值用作 baseValue 用于新引用,然后使用()调用。由于此引用具有原始基值,因此在我的答案开头定义的语义适用。

答案 1 :(得分:2)

这正是它正在做的事情。

根据需要使用Javascript boxes原始类型。

以下是更多信息:

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

答案 2 :(得分:1)

the reference个文字转换为对象:

  

字符串文字(用双引号或单引号表示)和字符串   在非构造函数上下文中从String调用返回(即,没有   使用new关键字)是原始字符串。 JavaScript自动   转换基元和String对象,以便可以使用它   原始字符串的字符串对象方法。

答案 3 :(得分:0)

你几乎是对的。有一种称为自动装箱(在对象中包裹原语)http://princepthomas.blogspot.com/2011/07/auto-boxing-javascript-primitive-types.html


编辑:sory复制Mike Christensen链接 - 我没有注意到它。