2022 年 6 月 12 日

基元的方法

JavaScript 允许我们像处理对象一样处理基元(字符串、数字等)。它们还提供可调用的方法。我们很快会学习这些方法,但首先我们来看看它是如何工作的,因为当然,基元不是对象(这里我们会让它更清晰)。

我们来看看基元和对象之间的主要区别。

一个基元

  • 是原始类型的值。
  • 有 7 种原始类型:stringnumberbigintbooleansymbolnullundefined

一个对象

  • 能够将多个值存储为属性。
  • 可以使用 {} 创建,例如:{name: "John", age: 30}。JavaScript 中还有其他类型的对象:例如,函数就是对象。

关于对象最好的事情之一是,我们可以将一个函数存储为其属性之一。

let john = {
  name: "John",
  sayHi: function() {
    alert("Hi buddy!");
  }
};

john.sayHi(); // Hi buddy!

所以这里我们使用 sayHi 方法创建了一个对象 john

许多内置对象已经存在,例如那些处理日期、错误、HTML 元素等的对象。它们具有不同的属性和方法。

但是,这些功能是有代价的!

对象比原始类型“更重”。它们需要额外的资源来支持内部机制。

一个作为对象的原始类型

这是 JavaScript 创建者面临的悖论

  • 人们希望对原始类型(如字符串或数字)执行许多操作。使用这些方法访问它们会很棒。
  • 原始类型必须尽可能快且轻量级。

解决方案看起来有点尴尬,但它是这样的

  1. 原始类型仍然是原始类型。一个单一的值,正如所愿。
  2. 该语言允许访问字符串、数字、布尔值和符号的方法和属性。
  3. 为了实现这一点,会创建一个提供额外功能的特殊“对象包装器”,然后将其销毁。

每个原始类型的“对象包装器”都不同,它们被称为:StringNumberBooleanSymbolBigInt。因此,它们提供了不同的方法集。

例如,存在一个字符串方法 str.toUpperCase(),它返回一个大写的 str

它的工作原理如下

let str = "Hello";

alert( str.toUpperCase() ); // HELLO

很简单,对吧?以下是 str.toUpperCase() 中实际发生的事情

  1. 字符串 str 是一个原始类型。因此在访问其属性的那一刻,会创建一个特殊对象,该对象知道该字符串的值,并具有有用的方法,如 toUpperCase()
  2. 该方法运行并返回一个新字符串(由 alert 显示)。
  3. 特殊对象被销毁,只留下原始类型 str

因此,原始类型可以提供方法,但它们仍然保持轻量级。

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

一个数字有它自己的方法,例如,toFixed(n) 将数字四舍五入到给定的精度

let n = 1.23456;

alert( n.toFixed(2) ); // 1.23

我们将在章节 数字字符串 中看到更具体的方法。

构造函数 String/Number/Boolean 仅供内部使用

像 Java 这样的某些语言允许我们使用类似 new Number(1)new Boolean(false) 的语法显式地为基元创建“包装对象”。

在 JavaScript 中,出于历史原因,这也是可能的,但强烈不推荐。很多地方都会变得混乱。

例如

alert( typeof 0 ); // "number"

alert( typeof new Number(0) ); // "object"!

对象在 if 中始终为真,因此此处警报将显示

let zero = new Number(0);

if (zero) { // zero is true, because it's an object
  alert( "zero is truthy!?!" );
}

另一方面,在没有 new 的情况下使用相同的函数 String/Number/Boolean 完全没问题且有用。它们将值转换为相应类型:字符串、数字或布尔值(基元)。

例如,这是完全有效的

let num = Number("123"); // convert a string to number
null/undefined 没有方法

特殊基元 nullundefined 是例外。它们没有相应的“包装对象”,也不提供任何方法。从某种意义上说,它们是“最原始的”。

尝试访问此类值的属性将导致错误

alert(null.test); // error

总结

  • 除了 nullundefined 之外的基元提供了许多有用的方法。我们将在即将到来的章节中学习这些方法。
  • 从形式上讲,这些方法通过临时对象工作,但 JavaScript 引擎经过精心调整以在内部优化它们,因此调用它们并不昂贵。

任务

重要性:5

考虑以下代码

let str = "Hello";

str.test = 5;

alert(str.test);

您认为它会起作用吗?会显示什么?

尝试运行它

let str = "Hello";

str.test = 5; // (*)

alert(str.test);

根据您是否使用 use strict,结果可能是

  1. undefined(非严格模式)
  2. 错误(严格模式)。

为什么?让我们重播在行 (*) 中发生的事情

  1. 当访问 str 的属性时,将创建一个“包装对象”。
  2. 在严格模式下,写入它是一个错误。
  3. 否则,将继续使用该属性进行操作,对象将获得 test 属性,但在之后“包装对象”将消失,因此在最后一行中 str 没有该属性的任何痕迹。

此示例清楚地表明基元不是对象。

它们无法存储附加数据。

教程地图

评论

在评论前请阅读此内容...
  • 如果您有改进建议,请提交 GitHub 问题或提交拉取请求,而不是评论。
  • 如果您无法理解文章中的内容,请详细说明。
  • 要插入少量代码,请使用 <code> 标记,对于多行代码,请将其包装在 <pre> 标记中,对于 10 行以上的代码,请使用沙盒 (plnkrjsbincodepen...)