字符串对象与字符串字面量:修改原型?

5

我想知道为什么似乎在字符串字面量的原型中添加方法似乎有效,但添加属性则不行? 我正在研究与此问题有关的想法,并编写了以下代码:

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));
​

这个很好用。但是,如果我将倒数第三行改为:

var testString = 'Loremipsumdolorsitamet,consectetur';

看起来尽管方法_str_substr存在且可以在字符串文字上调用,但属性_str_index1的值始终为0。

怎么回事?


你所称呼的“字符串字面量”中,大部分 实际上被称为“字符串原始值”:字面量是一种语法,用于描述一个字符串,例如将一个字符串(或数字、布尔值、对象等)赋值给一个变量;原始值是变量和对象可以包含的非复合值(除了(其他)对象)。 - Marcel Korpel
除非出现特殊情况,否则对字符串调用“indexOf”函数时会出现“indexOf不是一个函数”的错误。 - Cris Stringfellow
2个回答

9
每次尝试调用 String 对象的方法时(当必要时,JavaScript 引擎会将字符串原始值转换为 String 对象),原始字符串都会被转换为短暂的 String 对象。此函数返回后,String 对象会在幕后被(不显眼地)转换回字符串原始值,并返回这个新的原始值(大多数情况下会被赋给一个变量);每次调用 String 对象的方法时 都会这样做。
所以,在每次调用 testString._str_substr 后,_str_index1 与对象一起被丢弃,并在再次调用 _str_substr 时创建一个新对象(带有重置的 _str_index1)。
另请参见 MDC

因为 JavaScript 自动在字符串原始值和 String 对象之间进行转换,所以您可以在字符串原始值上调用 String 对象的任何方法。JavaScript 自动将字符串原始值转换为临时的 String 对象,调用方法,然后丢弃临时 String 对象。


是的,那基本上就是我想说的 :) - Dagg Nabbit

2
这是因为在赋值时该对象被创建并立即丢弃,因为它是一个字符串字面量。
所以第一个版本中,对象被创建并保留,所以testString是一个对象,而不是字符串字面量。在第二种情况下,对象被创建并丢弃,因此所有属性都会丢失...
现在尝试将该行替换为以下内容:
var testString = 'Loremipsumdolorsitamet,consectetur'._str_substr();

有趣,对吧?它仍然返回一个字符串基元,但这可以修复...
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);
};

当然,这些只是建议,旨在帮助解释为什么文字的行为与对象不同,并非现实世界中的建议...

我也不知道。@不好意思,我不明白你的意思。 - sje397
“the object is created and immediately thrown away when the assignment is made”听起来像是在初始赋值(var testString = …)时创建并丢弃对象,而不是在调用_str_substr时。 - Marcel Korpel
嗯,我正在 ECMAScript 规范中寻找它,但是找不到(至少在这个时候找不到)。但如果是这种情况,那么 String 对象的方法不能在字符串赋值后调用。每次调用 String 对象的方法时,都必须将字符串原始值转换一次。 - Marcel Korpel
Marcel:我认为我们在谈论同一件事情...据我所知,当遇到字符串时,会临时创建一个String对象,然后将其丢弃。也许我对此有所错误,但重点是它不是从声明时就是一个对象,它是一个原始类型;除了它的值之外没有状态。当您调用字符串原始类型的'methods'时,就像将String.prototype.x应用于字面字符串一样。 - Dagg Nabbit
你是正确的(关于我们正在讨论同一件事)。 - Marcel Korpel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接