JavaScript中字符串原语和字符串对象之间的区别是什么?

JavaScript中字符串原语和字符串对象之间的区别是什么?,javascript,string,object,Javascript,String,Object,取自 字符串文字(用双引号或单引号表示)和字符串 从非构造函数上下文中的字符串调用返回(即,没有 使用新关键字)是基本字符串。自动JavaScript 将基本体转换为字符串对象,以便可以使用 基本字符串的字符串对象方法。在 方法将在基元字符串或属性查找上调用 发生时,JavaScript将自动包装字符串原语并 调用该方法或执行属性查找 因此,我认为(逻辑上)对字符串原语的操作(方法调用)应该比对字符串对象的操作慢,因为在对字符串应用方法之前,任何字符串原语都会转换为字符串对象(额外工作) 但在这

取自

字符串文字(用双引号或单引号表示)和字符串 从非构造函数上下文中的字符串调用返回(即,没有 使用新关键字)是基本字符串。自动JavaScript 将基本体转换为字符串对象,以便可以使用 基本字符串的字符串对象方法。在 方法将在基元字符串或属性查找上调用 发生时,JavaScript将自动包装字符串原语并 调用该方法或执行属性查找

因此,我认为(逻辑上)对字符串原语的操作(方法调用)应该比对字符串对象的操作慢,因为在对字符串应用
方法之前,任何字符串原语都会转换为字符串对象(额外工作)

但在这方面,结果却是相反的。代码块-1代码块-2运行得更快,两个代码块如下所示:

代码块1:

var s = '0123456789';
for (var i = 0; i < s.length; i++) {
  s.charAt(i);
}
var s = new String('0123456789');
for (var i = 0; i < s.length; i++) {
    s.charAt(i);
}
var s='0123456789';
对于(变量i=0;i
代码块-2:

var s = '0123456789';
for (var i = 0; i < s.length; i++) {
  s.charAt(i);
}
var s = new String('0123456789');
for (var i = 0; i < s.length; i++) {
    s.charAt(i);
}
var s=新字符串('0123456789');
对于(变量i=0;i
结果在浏览器中有所不同,但是代码块-1总是更快。任何人都可以解释一下,为什么当您声明:

var s = '0123456789';
您可以创建一个字符串原语。该字符串原语有一些方法,可以在不将原语转换为第一类对象的情况下对其调用方法。因此,由于字符串必须转换为对象,因此您认为这会更慢的假设是不正确的。它不必转换为对象。原语本身可以调用这些方法


将其转换为一个完整的对象(允许您向其添加新属性)是一个额外的步骤,并不会使字符串操作更快(事实上,您的测试表明这会使它们更慢)。

如果使用
新建
,则明确表示您要创建对象的实例。因此,
newstring
正在生成一个包装String原语的对象,这意味着对它的任何操作都需要额外的一层工作

typeof new String(); // "object"
typeof '';           // "string"

由于它们的类型不同,您的JavaScript解释器也可能以不同的方式对它们进行优化。

对象的存在与ECMAScript/JavaScript引擎中字符串的实际行为没有多大关系,因为根作用域将仅包含用于此目的的函数对象。因此,将搜索并执行字符串文本的charAt(int)函数

对于一个真实的对象,您可以再添加一层,在标准行为开始之前,charAt(int)方法也会在对象本身上进行搜索(同上)。显然,在这种情况下,有大量的工作要做


顺便说一句,我不认为原语实际上被转换成了对象,但是脚本引擎会简单地将这个变量标记为字符串类型,因此它可以找到为它提供的所有函数,这样看起来就像你调用了一个对象。不要忘记,这是一个脚本运行时,它的工作原理与OO运行时不同。

JavaScript有两个主要类型类别,primivites和objects

var s = 'test';
var ss = new String('test');
单引号/双引号模式在功能上是相同的。除此之外,您试图命名的行为称为自动装箱。所以实际发生的情况是,当调用包装器类型的方法时,原语被转换为其包装器类型。简单来说:

var s = 'test';
是一种基本数据类型。它没有方法,只不过是指向原始数据内存引用的指针,这解释了更快的随机访问速度

例如,当你做s.charAt(i)
时会发生什么

由于
s
不是
String
的实例,JavaScript将自动将
s
框起来,它将
typeof String
typeof object
或更准确地说
s.valueOf(s).prototype.toString.call=[object String]

自动装箱行为根据需要将
s
来回转换为其包装类型,但是标准操作速度非常快,因为您处理的是一种更简单的数据类型。但是,自动装箱和
Object.prototype.valueOf
具有不同的效果


如果要强制自动装箱或将原语强制转换为其包装器类型,可以使用
Object.prototype.valueOf
,但行为不同。基于各种各样的测试场景,自动装箱仅应用“必需”方法,而不改变变量的原始性质。这就是为什么您可以获得更好的速度。

这相当依赖于实现,但我将试一试。我将以V8为例,但我假设其他发动机使用类似的方法

字符串原语被解析为对象。因此,如jfriend00所述,可以直接在其上调用方法

另一方面,字符串对象被解析为一个扩展了
对象
,除了作为一个完整的对象之外,还充当
v8::String
的包装器

现在它只是符合逻辑的,调用
新字符串(“”).method()
必须在执行该方法之前取消对该
v8::StringObject
v8::String
的装箱,因此速度较慢


在许多其他语言中,基元值没有方法

MDN的说法似乎是解释原语自动装箱如何工作的最简单方式(正如弗拉夫的回答中提到的),即JavaScript的primitive-y值如何调用方法

但是,智能引擎不会在每次需要调用方法时将字符串原语-y转换为字符串对象。这是
var a = new String("s");
var b = new String("s");
var x = "hello" ;
x.y = "world";
console.log(x.y); // this will print undefined
var x = new String("hello");
x.y = "world";
console.log(x.y); // this will print world
"hello" == "hello"
-> true
new String("hello") == new String("hello") // beware!
-> false
console.log( a.toUpperCase() ); or console.log( a.toLowerCase() );
let justString = 'Hello From String Value';
justString.addNewProperty = 'Added New Property';
console.log( justString );
let justString = 'Hello From String Value';
let wrapperObject = new String( justString );
wrapperObject.addNewProperty = 'Added New Property'; //Do operation and discard
var StringObj = new String("third way")
var StringObj2 = new String("third way")
StringObj  == StringObj2 // no result will be false, because they have different references