重学前端—JavaScript(二)

430 阅读7分钟

这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战

重学前端-JavaScript(1)

重学前端-JavaScript(2)

重学前端-JavaScript(3)

重学前端-JavaScript(4)

重学前端-JavaScript(5)

重学前端-JavaScript(2)

1, 前言

在学习JavaScript之前,先想想下面的几个问题

1,为什么有的编程规范要求用 void 0 代替 undefined?

2,字符串有最大长度吗?

3,0.1 + 0.2 不是等于 0.3 么?为什么 JavaScript 里不是这样的?

4,ES6 新加入的 Symbol 是个什么东西?

5,为什么给对象添加的方法能用在基本类型上?

​ 如果你答起来还有些犹豫的地方,这就说明你对这部分知识点,还是有些遗漏之处的。我在前面提到过,我们的 JavaScript 模块会从运行时、文法和执行过程三个角度去剖析 JS 的知识体系,本篇我们就从运行时的角度去看 JavaScript 的类型系统

2,类型

JavaScript 语言规定了 7 种语言类型。语言类型广泛用于变量、函数参数、表达式、函数返回值等场合

UndefinedNullBooleanStringNumberSymbolObject

(1) 为什么有的编程规范要求用 void 0 代替 undefined?

Undefined 类型表示未定义,它的类型只有一个值,就是 undefined。
任何变量在赋值前是 Undefined 类型、值为 undefined,
一般我们可以用全局变量 undefined(就是名为 undefined 的这个变量)来表达这个值,
或者 void 运算来把任意一个表达式变成 undefined 值。

但是呢,因为 JavaScript 的代码 undefined 是一个变量,而并非是一个关键字,这是 JavaScript 语言公认的设
计失误之一,所以,我们为了避免无意中被篡改,我建议使用 void 0 来获取 undefined 值。

Undefined 跟 Null 有一定的表意差别,Null 表示的是:“定义了但是为空”。所以,在实际编程时,我们一般不会
把变量赋值为 undefined,这样可以保证所有值为 undefined 的变量,都是从未赋值的自然状态。

Null 类型也只有一个值,就是 null,它的语义表示空值,与 undefined 不同,null 是 JavaScript 关键字,所
以在任何代码中,你都可以放心用 null 关键字来获取 null 值。

(2) 字符串有最大长度吗?

String 用于表示文本数据。String 有最大长度是 2^53 - 1

(3) 0.1 + 0.2 不是等于 0.3 么?为什么 JavaScript 里不是这样的?

浮点型运算由于有精度,就导致0.1+0.2!=0.3,可以用Math.abs(0.1+0.2-0.3)<=Number.EPSILON 

(4) ES6 新加入的 Symbol 是个什么东西?

SymbolES6引入的新类型,它是一切非字符串的对象key的集合,不支持new方法,特点是返回的symbol值都是唯一的 


(5)为什么给对象添加的方法能用在基本类型上?

每一个基本类型都在对象中有相应的类(除了symbol,但是可以装箱转换),因为运算符提供了装箱操作,它会根据基
本类型构造一个临时对象,所以在基础类型上可以调用对应对象的方法

3,类型转换

​ 因为 JS 是弱类型语言,所以类型转换发生非常频繁,大部分我们熟悉的运算都会先进行类型转换。大部分类型转换符合人类的直觉,但是如果我们不去理解类型转换的严格定义,很容易造成一些代码中的判断失误。其中最为臭名昭著的是 JavaScript 中的“ == ”运算,因为试图实现跨类型的比较,它的规则复杂到几乎没人可以记住。这里我们当然也不打算讲解 == 的规则,它属于设计失误,并非语言中有价值的部分,很多实践中推荐禁止使用“ ==”,而要求程序员进行显式地类型转换后,用 === 比较

1637936276033.png ​ 除了这七种语言类型,还有一些语言的实现者更关心的规范类型。

  • List 和 Record: 用于描述函数传参过程。
  • Set:主要用于解释字符集等。
  • Completion Record:用于描述异常、跳出等语句执行过程。
  • Reference:用于描述对象属性访问、delete 等。
  • Property Descriptor:用于描述对象的属性。
  • Lexical Environment 和 Environment Record:用于描述变量和作用域。
  • Data Block:用于描述二进制数据。

4,面向对象

  • 对象具有唯一标识性:即使完全相同的两个对象,也并非同一个对象。
  • 对象有状态:对象具有状态,同一对象可能处于不同状态之下。
  • 对象具有行为:即对象的状态,可能因为它的行为产生变迁。

(1)唯一标志性

​ 我们先来看第一个特征,对象具有唯一标识性。一般而言,各种语言的对象唯一标识性都是用内存地址来体现的, 对象具有唯一标识的内存地址,所以具有唯一的标识。所以,JavaScript 程序员都知道,任何不同的 JavaScript 对象其实是互不相等的

在 JavaScript 中,对象的状态和行为其实都被抽象为了属性。

在实现了对象基本特征的基础上, 我认为,JavaScript 中对象独有的特色是:对象具有高度的动态性,这是因为 JavaScript 赋予了使用者在运行时为对象添改状态和行为的能力。

(2)两类属性

​ 先来说第一类属性,数据属性。它比较接近于其它语言的属性概念。数据属性具有四个特征。

value:就是属性的值。
writable:决定属性能否被赋值。
enumerable:决定 for in 能否枚举该属性。
configurable:决定该属性能否被删除或者改变特征值。
在大多数情况下,我们只关心数据属性的值即可。

第二类属性是访问器(getter/setter)属性,它也有四个特征

getter:函数或 undefined,在取属性值时被调用。
setter:函数或 undefined,在设置属性值时被调用。
enumerable:决定 for in 能否枚举该属性。
configurable:决定该属性能否被删除或者改变特征值。

访问器属性使得属性在读和写时执行代码,它允许使用者在写和读属性时,得到完全不同的值,它可以视为一种函数的语法糖。我们通常用于定义属性的代码会产生数据属性,其中的 writable、enumerable、configurable 都默认为 true。

我们可以使用内置函数 getOwnPropertyDescriptor 来查看,如以下代码所示:

var o = { a: 1 };
o.b = 2;
    //a和b皆为数据属性
 Object.getOwnPropertyDescriptor(o,"a") 
 // {value: 1, writable: true, enumerable: true, configurable: true}
 Object.getOwnPropertyDescriptor(o,"b") 
  // {value: 2, writable: true, enumerable: true, configurable: true}

如果我们要想改变属性的特征,或者定义访问器属性,我们可以使用 Object.defineProperty,示例如下:

var o = { a: 1 };
Object.defineProperty(o, "b", {value: 2, writable: false, enumerable: false, configurable: true});
    //a和b都是数据属性,但特征值变化了
Object.getOwnPropertyDescriptor(o,"a");
// {value: 1, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(o,"b");
// {value: 2, writable: false, enumerable: false, configurable: true}
o.b = 3;
console.log(o.b); // 2

​ 这里我们使用了 Object.defineProperty 来定义属性,这样定义属性可以改变属性的 writable 和 enumerable。

​ 我们同样用 Object.getOwnPropertyDescriptor 来查看,发现确实改变了 writable 和 enumerable 特征。因为 writable 特征为 false,所以我们重新对 b 赋值,b 的值不会发生变化。

在创建对象时,也可以使用 get 和 set 关键字来创建访问器属性,代码如下所示:

var o = { get a() { return 1 } };
 console.log(o.a); // 1

5, 总结

​ 要想理解 JavaScript 对象,必须清空我们脑子里“基于类的面向对象”相关的知识,回到人类对对象的朴素认知和面向对象的语言无关基础理论,我们就能够理解 JavaScript 面向对象设计的思路。