事不宜迟,让我们继续我们的JavaScript世界之旅!
image.png
在上一节中,我们数了Undefined, Null, Booleans和Numbers类型。现在,我们将继续从BigInts开始数类型。

BigInts

image.png
BigInts只是最近才添加到JavaScript,因此你不会看到它们被广泛使用。如果你使用的是旧版浏览器,这个类型将无法使用。常规数字类型不能精确地表示大整数,因此BigInts(从字面意义上)填补了这一空白

  1. let alot = 9007199254740991n; // Notice n at the end
  2. console.log(alot + 1n); // 9007199254740992n
  3. console.log(alot + 2n); // 9007199254740993n
  4. console.log(alot + 3n); // 9007199254740994n
  5. console.log(alot + 4n); // 9007199254740995n
  6. console.log(alot + 5n); // 9007199254740996n

四舍五入可不是闹着玩的!这对于精度特别重要的财务计算非常有用。记住,没有什么是免费的。数量巨大的操作可能需要更多的时间和资源。
在我们的世界中有多少个BigInts?规范上说它们的精度是任意的。这意味着在我们的JavaScript世界中,有无数个bigint —- 数学中每个整数对应一个bigint
是的…
如果这听起来很奇怪,考虑一下你已经习惯了数学中有无限整数的概念(如果你没有,那就思考几分钟!)。从“数学世界”到“JavaScript世界”的跨越并不大。

Strings

image.png
字符串表示JavaScript中的文本。有三种写字符串的方法(单引号,双引号和反引号),但结果是相同的:

  1. console.log(typeof("こんにちは")); // "string"
  2. console.log(typeof('こんにちは')); // "string"
  3. console.log(typeof(`こんにちは`)); // "string"

空字符串也是字符串:

  1. console.log(typeof('')); // "string"

字符串不是对象

所有字符串都有一些内置属性。

  1. let cat = 'Cheshire';
  2. console.log(cat.length); // 8
  3. console.log(cat[0]); // "C"
  4. console.log(cat[1]); // "h"

这并不意味着字符串是对象!字符串属性是特殊的,它的行为与对象属性不同。例如,您不能将任何内容分配给cat[0]。字符串是基本类型,所有基本类型都是不可变的。

每个可以想到的字符串都有一个值

在我们的宇宙中,每一个可以想到的字符串都有一个不同的值。是的,这包括你祖母的娘家姓,你十年前化名出版的同人小说,还有《黑客帝国5》还没写的剧本。
当然,所有可能的字符串都不能真正地放入计算机内存芯片中。但每一个可能的字符串的概念可以装进你的脑袋。我们的JavaScript世界是相对于人类的一个模型,不是计算机的!
这可能会引发一个问题。下面这段代码创建了一个字符串吗?

  1. // Try it in your console
  2. let answer = prompt('Enter your name');
  3. console.log(answer); // ?

还是仅仅召唤我们世界中已经存在的字符串?
这个问题的答案取决于我们是“从外部”还是“从内部”学习JavaScript。
在我们的思维模型之外,答案取决于特定的实现。字符串是表示为一个内存块,多个块还是一个rope数据结构,取决于JavaScript引擎。
但在我们的思维模式中,这个问题没有任何意义。我们无法设置一个实验来判断在JavaScript世界中字符串是“被创建”还是“被调用”。
为了简化我们的思维模型,我们将说所有可能的字符串值从一开始就已经存在-每个不同的字符串都有一个值。

Symbols

Symbol是相对较新的类型。

  1. let alohomora = Symbol();
  2. console.log(typeof(alohomora)); // "symbol"

在不深入研究对象和属性的情况下很难解释它们的目的和行为,因此现在我们将跳过它们。抱歉,Symbol!
image.png

Objects

image.png
最后,我们来到了对象这儿!
这包括数组,日期,正则和其他非原始值:

  1. console.log(typeof({})); // "object"
  2. console.log(typeof([])); // "object"
  3. console.log(typeof(new Date())); // "object"
  4. console.log(typeof(/\d+/)); // "object"
  5. console.log(typeof(Math)); // "object"

与之前的一切不同,对象不是原始值。这也意味着默认情况下,它们是可变的。我们可以使用’.’或者’[]’访问它们的属性:

  1. let rapper = { name: 'Malicious' };
  2. rapper.name = 'Malice'; // Dot notation
  3. rapper['name'] = 'No Malice'; // Bracket notation

我们还没有详细讨论属性,所以你对它们的思维模型可能是模糊的。我们将在以后的章节中讨论属性。

创建自己的对象

有一件事特别让Count von Count兴奋。我们可以创造更多对象!我们可以创建自己的对象。
在我们的思维模型中,我们讨论过的所有原始类型——null、undefined、boolean、number和string——都“一直存在”。我们不能“制造”一个新的字符串或一个新的数字,我们只能“召唤”那个值:

  1. let sisters = 3;
  2. let musketeers = 3;

image.png
使对象与众不同的是,我们可以创建更多对象。每次我们使用{}面向字面量时,我们都会创建一个全新的对象值:

  1. let shrek = {};
  2. let donkey = {};

image.png
数组,日期和任何其他对象也是如此。例如,[]数组文字会创建一个新的数组值-一个以前不存在的值。
你可能会想:对象会消失吗?或者它们会永远存在吗?JavaScript的设计方式使我们无法从代码中分辨出其中的一种方式。例如,我们不能销毁一个对象:

  1. let junk = {};
  2. junk = null; // Doesn't necessarily destroy an object

相反,JavaScript是一种垃圾收集语言。
这意味着,尽管我们无法销毁某个对象,但如果无法通过遵循代码中的连线来到达该对象,则该对象最终可能会“消失”。
garbagecollection-optim.gif
JavaScript不能保证垃圾收集何时发生。
除非你想弄清楚为什么一个应用程序占用了太多内存,否则你不需要经常考虑垃圾回收。我在这里提到它只是为了让你知道我们可以创造对象——但我们不能销毁它们。
在我们的世界中,对象和函数是最接近我的代码。这提醒了我,我可以操作它们,甚至更多地利用它们。

Functions

image.png
将函数看作与我的代码分离的值是特别奇怪的,毕竟,它们是我的代码,难道不是吗?

函数就是值

我们定义函数,以便稍后调用它们并在其中运行代码。然而,要真正理解JavaScript中的函数,我们需要暂时忘记它们的用处。相反,我们将函数看作另一种类型的值:一个数字、一个对象、一个函数。
为了理解函数,我们将把它们与数字和对象进行比较。
首先,考虑运行console.log(2)七次的for循环:

  1. for (let i = 0; i < 7; i++) {
  2. console.log(2);
  3. }

它传递给console.log多少个不同的值?为了回答这个问题,我们回忆一下2是什么意思。它是一个字面意义上的数字。字面意思是一种表达——对我们世界的一个问题。在我们的世界中,每个数字只有一个值,所以它通过每次“召唤”数字2的相同值来“回答”我们的问题。所以答案是一个值。我们将看到7次log—但是我们在每个调用中传递相同的值。
现在,让我们简要回顾一下对象。
这是另一个运行console.log({})七次的for循环:

  1. for (let i = 0; i < 7; i++) {
  2. console.log({});
  3. }

现在它向console.log传递了多少个不同的值?这里,{}也是一个字面量——除了它是一个对象字面量。正如我们刚刚了解到的,JavaScript世界不会通过调用任何东西来“回答”一个对象的字面量。相反,它创建一个新的对象值——它将是{}对象字面量的结果。因此上面的代码创建并记录了七个完全不同的对象值。
明白这一点。
现在我们来看看函数。

  1. for (let i = 0; i < 7; i++) {
  2. console.log(function() {});
  3. }

此代码将多少个不同的值传递给console.log?
在确定答案之前,请勿进一步滚动
























答案是七个。
每当我们执行包含函数表达式的代码行时,就会在我们的世界中出现一个全新的函数值。
function-creation-optim-v2.gif

这里,function(){}也是一个表达式。与任何表达式一样,函数表达式也是JavaScript世界的一个“问题”——它通过在每次请求时创建一个新函数值来回答我们。这与{}在执行时创建新对象值的方式非常相似,函数就像对象一样!
从技术上讲,函数是JavaScript中的对象。我们将继续将它们作为单独的基本类型处理,因为与常规对象相比,它们具有独特的功能。但是,一般来说,如果你可以对一个对象做点什么,你也可以对一个函数做点什么,它们是非常特殊的对象。

调用函数

下面代码会打印什么?

  1. let countDwarves = function() { return 7; };
  2. let dwarves = countDwarves;
  3. console.log(dwarves);

你可能认为它打印7,特别是如果你不是很仔细地看。
现在在控制台中检查这个代码片段!它打印的确切内容取决于浏览器,但是你将看到函数本身,而不是数字7。
如果你遵循我们的思维模式,这种行为应该是有意义的:
1.首先,我们使用function(){}表达式创建一个新的函数值,并将count变量指向这个值。
2.接下来,我们将dwarf变量指向count所指向的值,即相同的函数值。
3.最后,我们记录了dwarf当前所指向的值。

我们根本没有调用我们的函数!
_
因此,countdwarf和dwarf都指向相同的值,而该值恰好是一个函数。这样看来,函数就是值。我们可以将变量指向它们,就像我们可以处理数字或对象一样。
当然,如果我们想调用一个函数,我们也可以这样做:

  1. let countDwarves = function() { return 7; };
  2. let dwarves = countDwarves(); // () is a function call
  3. console.log(dwarves);

注意,let声明和=赋值都与我们的函数调用无关。执行函数调用的是(),而且是单独执行的!
添加()会更改代码的含义:
let dwarfs = count的意思是“让dwarfs指向count所指的值”。
let dwarfs = count()的意思是“将dwarfs指向count所指向的函数返回的值”。
事实上,count()也是一个表达。它被称为调用表达式。要“回答”一个调用表达式,JavaScript在函数中运行代码,并将返回的值作为结果传递给我们(在本例中为7)。
我们将在以后的章节中更详细地讨论函数调用。

总结

这真是一段难忘的旅程!在前两节中,我们研究了JavaScript中的每种值类型。让我们加入Count von Count来概括每种类型有多少个值,从不同的基本类型开始:
image.png

  • Undefined: 只有一个值,未定义。
  • Null: 只有一个值,Null。
  • Boolean: 两个值:真和假。
  • Number: 每个浮点数对应一个值。
  • BigInt: 每一个可以想到的整数对应一个值。
  • String: 每个字符串对应一个值。
  • Symbol: 我们现在跳过符号,但总有一天会讲到它们!

下面的类型很特别,因为它们让我们可以创建自己的值:
image.png

  • Object: 我们执行的每一个对象字面量都是一个值。
  • Function: 我们执行的每个函数表达式都是一个值。

参观不同的JavaScript“天体”非常有趣。现在我们已经数出了所有的值,我们也知道了是什么使它们彼此不同。例如,写入2或“hello”总是“”相同的数字或字符串值。但是编写{}或function(){}总是会创建一个全新的、不同的值。这个概念对于理解JavaScript中的等式非常重要,这将是下一个章节的主题。

练习

本节还包含练习供你练习!

点击此处,通过一些简短的练习来巩固这种思维模型。
不要跳过它们!
即使你可能熟悉不同类型的值,这些练习也将帮助你巩固我们正在构建的思维模型。在进入更复杂的主题之前,我们需要这个基础。
完成练习后,我将发送下一个章节。

Cheers,
Dan.