通过ECM-262规范学习Javascript--------一、基本类型

如果在阅读本文的过程中,因为排版或样式问题感到不快,可以在这里阅读原文(VuePress)。

本规范中的算法处理每个值都有关联类型的值。可能的值类型正是本节中定义的值类型。类型又进一步细分为ECMAScript语言类型(language types)和规范类型(specification types)。

规范中定义的的语言类型有[Undefined, Null, Boolean, String, Symbol, Number](基本类型),和Object(引用类型).

Undefined类型

Undefined类型仅有一个值,被称为undefined。任何尚未分配值的变量都是undefined

扩展阅读: void 0和undefined

  在很多种书籍中我们可能会见过void 0这样的表达式,通常这个表达式用在代替undefined的位置。那么为什么要使用void 0代替undefined?因为undefined可以被重写,被重写后的undefined会失去他本来的意思,所以会引起一些难以定位的错误。

  当然,在部分文章中会有undefined在现代浏览器已经无法被重新赋值,所以提出void 0的意义并不大,我们可以看下面这个例子:


var undefined = 12345

console.log(undefined)  // undefined

按照上面代码运行的结果来看,好像undefined确实不能被重新赋值了。但是如果我们在一个块级作用域或函数作用域里给undefined进行赋值,会发生什么事?

function foo(num){
  let undefined = 123;

  if(num !== undefined){
    // do sth.
  }else{
    console.log('请传入正确的变量num')
  }
}

foo(123) // 请传入正确的变量num

  在开发场景中我们会经常使用类似num !== undefined这种方式去判断是否传入了参数。

  上边这段代码,在函数体第一行声明了一个叫做undefined的变量并赋值为123;在我们调用foo(123)的时候,发现控制台打印出了请传入正确的变量num,证明在函数体内undefined的值已经被重写。

  所以if判断为false直接进入了else语句

{
  let undefined = 123;

  console.log(123 === undefined) // true
}

  执行上面的代码我们发现,控制台会输出true

  根据以上结论,我们推测出如下结论:在全局作用域中,undefined是不可修改的。但是函数作用域和块级作用域中,undefined是可修改的。当然,由于let和const有一些奇葩,我也在全局作用域中测试了用let/const声明并修改undefined的值,结果符合预期,具体就不多赘述了。感兴趣的同学可以自己试一试。

btw,如果在函数中修改了undefined的值,然后return undefined。函数的返回值是修改后的undefined的值,如果直接return;则会返回正确的undefined;可以参考规范**The return Statement部分

undefined在各浏览器的表现

  全局作用域中undefined在chrome/firefox/ie9及以上版本均不可修改,在IE8可以对全局作用域下的undefined进行修改

  通过Object.getOwnPropertyDescriptor方法查看下undefined属性描述:

undefined

  可以发现,window.undefined是一个不可修改不可配置不可枚举的三不属性。

  但是在IE8下(IE8可以修改全局作用域的undefined的值),打印出来的结果:

undefined

  window.undefined的writable变成了true,所以这应该是导致undefined在IE8下可以被修改的罪魁祸首。(可能跟IE8当时实现的时候的ECMA规范有关,之后我会去翻一下老版本规范,有发现会在后文补充)

  所以void 0个人觉得还是有存在的意义,并且需要我们在特定的时候考虑采用void 0替换undefined。

  至于void 0或void(0),为什么是undefined,根据ECMA-262-The void Operator的描述。

The void Operator

UnaryExpression : void UnaryExpression

1. Let expr be the result of evaluating UnaryExpression.
2. Let status be GetValue(expr).
3. ReturnIfAbrupt(status).
4. Return undefined.


在ES2019的规范中,void操作符的计算值的方式如下:

UnaryExpression:voidUnaryExpression

1. Let expr be the result of evaluating UnaryExpression.
2. Perform ? GetValue(expr).
3. Return undefined.

  在规范中有一句:

GetValue must be called even though its value is not used because it may have observable side-effects.即使不使用GetValue,也必须调用它,因为它可能会有明显的副作用。(至于副作用是什么,我也布吉岛呀,希望有大佬可以解惑)

注意第4\3步,即无论void 之后的表达式是什么,void操作符最终都会返回undefined

Null类型

  Null类型只有一个值,被称为null。

  同作为基本类型中的一员,null和undefined有很多相似点比如:


undefined == null // ture;

undefined == false; // true

null == false // true

  当然也有JS中’=='操作符的锅?

  当然,他们也有很多不同点:

1. null是一个保留字(Reserved word)

  • 保留字(Reserved word) 在ECMA规范中由4部分组成:

    • 关键字(Keyword)

    • 为了在将来javascript的版本使用的保留字(Future Reserved Word)

    • null字面量(Null literal)

    • 布尔字面量(Boolean literal)也就是true/false。

规范中对保留字的定义是:保留字是一种不能用作标识符的IdentifierName(A reserved word is an IdentifierName that cannot be used as an Identifier),所以在对保留字进行赋值的时候会报synax error

在ES2015中,enumawait被作为未来的保留字写入规范。

  所以我们不能将一个保留字作为标识符


let true = 'sawyersven'  // Uncaught SyntaxError

let super = "i'm a super star" // Uncaught SyntaxError

let enum = "this is an enum" // Uncaught SyntaxError

let null = "this is null" // Uncaught SyntaxError

let await = "this is await" // this is await


2. typeof操作

typeof undefined的返回值是undefined

而 typeof null的返回值是"object",typeof null是object是一个历史错误(Brendan Eich说的)

从ES5制定开始就有动议将typeof null改为返回“null”(如启动node加上“–harmony_typeof”参数,即是如此),但是当前ES6标准草案仍然维持了原样。

table
(图片来自ECMA2015规范)

3. 表达的意思不同

一般undefined。在声明了变量但是未初始化的时候,这个变量的值就是undefined。或者使用typeof+[一个未声明的变量]的时候会返回undefined(至于为什么typeof会出现这种怪异的表现,还是可以翻阅ECMA规范找到答案,之后的文章应该也会有(应该吧…))。

而null按照高程的描述:一个空对象指针,所以typeof null时会返回object,其值为null,可用于对象初始化或把对象置空

Boolean类型

Boolean型表示具有两个值的逻辑实体,分别称为true和false。

由于Boolean型比较简单,所以在这里不过多赘述。

String(字符串)类型

规范中描述String类型的特征如下:

字符串类型是0个或多个16位(bit)无符号整数值(“element”)的所有有序序列的集合,最大长度为2^53-1个元素的长度。String类型通常用于表示正在运行的ECMAScript程序中的文本数据。

在这种情况下,String中的每个元素都被视为一个UTF-16码元(code unit)。每个元素被认为在序列中占据一个位置。

这些位置用非负整数索引。第一个元素(如果有)位于索引0,下一个元素(如果有)位于索引1,依此类推。

字符串的长度是其中的元素数(即16位值)。空字符串的长度为零,因此不包含任何元素。

Symbol类型

Symbol类型是所有非字符串值的集合,可以用作Object属性(6.1.7)的键。

每个Symbol的值都是唯一且不可变的。

每个Symbol值永远地保持一个与之关联的叫做[[Description]]的值,它要么是undefined要么是一个字符串值。

关于Symbol可以参考MDN阮一峰老师的ECMAScript6标准入门

Number类型

Number类型正好具有18437736874454810627(即264−253 + 3)个值,表示IEEE二进制浮点算术标准中指定的双精度64位格式IEEE 754-2008的值,除了9007199254740990 (即2^53 - 2)是一个IEEE规范中截然不同的“Not-a-Number(即NaN)值,在ECMAScript中被作为一个特殊字符NaN值(请注意,NaN值是由程序表达式NaN产生的。)

在某些实现中,外部代码可能能够检测到各种NaN值之间的差异,但是这种行为取决于实现。对于ECMAScript代码,所有NaN值彼此之间是无法区分的(也就是说NaN === NaN是false)。

JS中的一个经典问题,0.1+0.2 !== 0.3可以参考从0.1+0.2=0.30000000000000004再看JS中的Number类型

本章小结

  本章主要内容是ECMAScript中语言类型中的基本数据类型,复习了6种基础类型的定义并且通过阅读规范梳理了部分数据类型在使用中发生一些容易被我们忽视的表现的原因,文中均有详细的描述,简单总结如下:

为什么推荐使用void 0代替undefined?void 0为什么等于undefined?

第一问,原因如下:

  • 全局作用域

    在IE9及以上版本和大多数现代浏览器中,undefined在全局作用域中不可以被重新赋值,但是在IE8及以下是可以被重新赋值的。

  • 函数/块级作用域

    在测试中chrome/77.0.3865.90的undefined在块级作用域和函数作用域中均可以被重新赋值,从而会产生一些预想不到的BUG。

    综上所述,void 0代替undefined是有意义的,并且在不确定undefined的值是否被修改的情况下推荐使用void表达式来代替undefined

第二问:在ECMA规范中对于void表达式的求值过程中,最后一步必然会返回undefined,所以void 0是undefined,见The void Operator

为什么undefined可以作为标识符,但是null不可以

虽然undefined和null给我们的感觉很像,但是实际上null在ECMAScript中是一个保留字(reserved word),但是undefined并不是,所以对null进行赋值会报错。

ECMA中的保留字定义为:关键字、未来的保留字、Null字面量、布尔字面量

0.1+0.2 !== 0.3(文章链接)

从0.1+0.2=0.30000000000000004再看JS中的Number类型

一个小问题:为什么可以对await和yield(ES2015中给未来的保留字)赋值,并且不会出错

  在ECMA-262 6.0版本中,await关键字是被作为一个Future Reserved Word写入规范的,但是为什么上面的例子中最后一行代码并没有报错并且赋值成功了?

在查阅文档的时候,参照了ECMA-262的5.1、2015、2019等版本,发现在保留字这边还有很多可以扩展的内容,比如规范2019中提到的let/static。此处做以标记,在之后的文章中补充。

我想说的话

  从一开始翻看ECMA规范,感觉发现宝藏的兴奋感。到第一篇写完。就我自己来说收获还是蛮多,在翻看文档和查阅相关资料的时候。其实也复习和学习了很多相关知识。并且写文章真的锻炼语言组织能力(我太菜了)。

尤其是关于String、Number和Symbol的内容,本来Stringn部分想讨论字符串字面量获取长度的时候的装箱过程,但是看着规范需要说明的概念有点多,又想真的说明白写在这篇文章里又不免啰嗦,只有之后单独整理成文。如果你看到这段话,万分感谢呢的耐心阅读,祝你头发乌黑浓密吧~~~??????

如果文章有任何错误或者遗漏之处,烦请务必指出,以免误导他人❤️❤️❤️。 本文撰写主要参考ECMA-262v6.0MDN,有部分内容参考搜索引擎搜索结果,如有侵权,请及时联系我删除。

发布了11 篇原创文章 · 获赞 4 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/kormondor/article/details/101330629