当我们在 JavaScript 中将原语视为对象时会发生啥?

Posted

技术标签:

【中文标题】当我们在 JavaScript 中将原语视为对象时会发生啥?【英文标题】:What happens when we treat primitives as objects in JavaScript?当我们在 JavaScript 中将原语视为对象时会发生什么? 【发布时间】:2021-09-26 13:53:35 【问题描述】:

我正在向javascript.info 学习 JS。现在我正在阅读Methods of primitives

当我们运行以下代码时

let str = 'hello';
alert( str.toUpperCase() ); // HELLO

在内部发生以下情况 (1) 创建一个特殊对象 (2) 复制 str 变量的值 (3) 修改复制的版本 (4) 在不触及原始 str 变量的情况下返回复制的版本 (5) 最后销毁该特殊对象。

作者是这么说的。但是当我们有这样的东西时

let str = 'Hello';
console.log(str.toUpperCase());          // HELLO
console.log(str.split('l'));             // (3) ["He", "", "o"]
console.log(str.startsWith('h'));        // false
console.log(str.concat(' JavaScript'));  // Hello JavaScript
console.log(str);                        // Hello

我只想知道,每次我们将原始对象视为对象时,是否都会创建一个特殊对象?从上面的代码中,我认为整个过程(创建一个对象,执行一些过程并销毁)执行了 4 次(因为我调用了 4 个方法)。

这是真的吗?

我也从中读到了以下内容

JavaScript 引擎高度优化了这个过程。它甚至可能完全跳过额外对象的创建。但它仍必须遵守规范并表现得好像它创造了规范一样。

这是什么意思?以上几行让我更加困惑整个过程完成了多少次。

【问题讨论】:

什么是“特殊对象”?是的,可能创建了许多对象,不查看源就无法知道,通常不应该关心。 感谢您的回答!我只想知道这个事实。现在我会继续前进:) 我不明白您所说的第 2 步“复制 str 变量的值”和 3“修改复制的版本”的意思。不涉及复制。 @Bergi 我认为复制是因为 str 变量的原始值在我调用 4 个方法后仍然保持不变。如果我错了,请纠正我。谢谢。 【参考方案1】:

我只想知道,每次我们将原始对象视为对象时,是否都会创建一个特殊对象?我在想整个过程做了4次,因为我调用了4个方法。

是的,没错。

JavaScript 引擎高度优化了这个过程。它甚至可能完全跳过额外对象的创建。但它仍必须遵守规范并表现得好像它创造了规范一样。

什么意思?

这意味着创建 4 个对象是浪费 - 一个就足够了,而且您仍然会得到相同的结果(在这种情况下)。该规范是以“表现得好像”的方式编写的,它不规范 javascript 引擎的实现需要如何逐步工作,而只规范它需要具有的可观察行为。如果一个引擎足够聪明,知道它可以跳过一个步骤,例如做不必要的副本或创建未使用的对象,那么只要执行结果仍然相同,它就可以这样做。

对于原始值的方法调用,这是一个相对简单的优化 - 引擎不需要实际在内存中分配对象,它可以直接跳到在假设的特殊对象上查找属性的步骤.

【讨论】:

感谢您的回答。我只想知道这个事实,因为我认为每种方法的整个过程都会影响性能。并且还说JS引擎对这个过程进行了高度优化。这就是为什么我变得困惑。现在很清楚了。

以上是关于当我们在 JavaScript 中将原语视为对象时会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

当字符串在双引号内有单引号时,如何在Javascript中将此字符串转换为JSON对象

在 Django 模型中将 NULL 视为“0”

JavaScript 中的字符串原语和字符串对象有啥区别?

我们可以在 javascript 中将通用对象转换为自定义对象类型吗?

如何在 AST 解析器中将类型解析为原语

在 Fabric.js 中将对象添加到画布时设置对象的位置