重学前端(二)
- 运行时类型是代码实际执行过程中我们用到的类型。所有的类型数据都会属于7个类型之一。从变量、参数、返回值到表达式中间结果,任何JavaScript代码运行过程中产生的数据,都具有运行时类型。
类型
Undefined
Null
Boolean
String
Number
Symbol
Object
Undefined
Null
Undefined
类型表示未定义,他的类型只有一个值,就是undefined
.任何变量在赋值前是Undefined
类型、值为undefined
,一般我们可以用全局变量undefined
(就是名为undefined
的这个变量)来表达这个值,或者void
运算来把任意一个表达式变成undefined
值Null
类型也只有一个值,就是null
,表示为控制,与undefined
不同
String
String
用于表示文本数据,最大长度为2^53 - 1
Number
-
Number
类型基本符合IEEE 754-2008
规定的双精度浮点数规则,根据浮点数的定义,非整数的Number
类型无法用 **== (===也不行)**来比较-
0.1 + 0.2 == 0.3 //输出 false
-
正确的比较方法:使用
JavaScript
提供的最小精度值 -
Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON
-
-
NaN,占用了 9007199254740990,这原本是符合IEEE规则的数字;
-
Infinity,无穷大;
-
-Infinity,负无穷大。
-
JavaScript
中有+0 和 -0 ,在假发类运算中它们没有区别,单数触发的场合则需要特别留意区分**,‘忘记检测除以-0,而得到负无穷大’**的情况经常会导致错误,而区分+0 和 -0 的方式,正式检测 1/x 是infinity
还是-infinity
Symbol
Symbol
是ES6
中引入的新类型,它是一切非字符串的对象key
的集合,在ES6
中,整个对象系统被用Symbol
重
Object
- 对象的定义是‘属性的集合’。属性分为数据属性和访问器属性,二者都是
key-value
结构,key
可以是字符串或者Symbol
类型 JS
中的类仅仅是运行时对象的一个私有属性,而JS
中时无法自定义类型的,在js
的几个基本类型中,都在对象类型中有一个亲戚
Number
String
Boolean
Symbol
- 所以,3 和
new Number(3)
是完全不同的值,它们是一个Number
类型,一个是对象类型,Number
、String
、Boolean
,三个构造器是俩用的,当跟new
搭配时,它们产生对象,当直接调用的时候,它们表示强制类型转换 - .(点)运算符提供了装箱操作,它会根据基础类型构造一个临时对象,使得我们能在基础类型上调用对应对象的方法
装箱转换
- 每一种基本类型
Number
、String
、Boolean
、Symbol
在对象中都有对应的类,所谓装箱转换,正是把基本类型转换为对应的对象,他是类型转换中一种相当重要的种类
拆箱转换
- 在JavaScript标准中,规定了
ToPrimitive
函数,它是对象类型到基本类型的转换(即,拆箱转换)。 - 对象到 String 和 Number 的转换都遵循“先拆箱再转换”的规则。通过拆箱转换,把对象变成基本类型,再从基本类型转换为对应的 String 或者 Number。
- 拆箱转换会尝试调用 valueOf 和 toString 来获得拆箱后的基本类型。如果 valueOf 和 toString 都不存在,或者没有返回基本类型,则会产生类型错误 TypeError。
总结
- List 和 Record: 用于描述函数传参过程。
- Set:主要用于解释字符集等。
- Completion Record:用于描述异常、跳出等语句执行过程。
- Reference:用于描述对象属性访问、delete等。
- Property Descriptor:用于描述对象的属性。
- Lexical Environment 和 Environment Record:用于描述变量和作用域。
- Data Block:用于描述二进制数据。
JavaScript
对象的特征
- 对象具有唯一标识性:即使完全相同的俩个对象,也并非同一个对象
- 对象有状态:对象具有状态,同一对象可能处于不同状态之下
- 对象具有信鸽网i:季对象的状态,可能因为它的行为产生变迁
(一)具有唯一标识性
- 各种语言的对象唯一标识性都是用内存地址来体现的,对象具有唯一表示的内存地址,所以具有唯一的标识
(二)第二 和 第三特征
-
在
JS
中,将状态和行为统一抽象为‘属性’,考虑到JavaScript
中函数设计成一种特殊对象 -
下面代码就展示了 普通属性 和 函数作为属性的一个例子,其中
o
是对象,d
是属性,而函数f
也是一个属性,尽管写法不太相同,但是对JavaScript
来说,d
和f
就是俩个普通属性 -
var o = { d:1, f(){ console.log(this.d) } }
JavaScript
中对象独有的特色是:对象具有高度的动态性,这是因为JS
赋予了使用者在运行是为对象添加状态和行为的能力
- 为了提高抽象能力,
JavaScript
的属性被设计成比别的语言更加复杂的形式,它提供了 数据属性和访问器属性(getter
/setter
)俩类
JavaScript
对象的俩类属性
数据属性具有四个特征
value
:就是属性的值writable
:决定属性能否被赋值enumerable
:决定for in
能否枚举该属性configurable
:决定改属性能否被删除或者改变特征值
访问器(getter
/ setter
)属性
getter
:函数 或者undefined
,在取属性值时被调用setter
:函数 或者undefined
,在设置属性值时被调用enumerable
:决定for in
能否枚举该属性configurable
:决定该属性能否被删除或者改变特征值
访问器属性是的属性在读和写时执行代码,它允许使用者在写和堵属性时,得到完全不同的值,它可以是为一种函数的语法糖
我们通常用于定义属性的代码会产生数据属性,其中的writable
、enumerable
、configurable
都会默认true
, 我们可以使用内置函数 Object.getOwnPropertyDescripter
来查看
JavaScript
对象的具体设计:具有高度动态性的属性集合
JavaScript
得原型
- 如果所有对象都有私有字段[[prototype]],就是对象的原型
- 读一个属性,如果对象本身没有,则会继续访问对象的原型,知道原型为空或者找到为止,(原型链)
ES6
,JS
提供了一系列内置函数,以便更为直接的访问操纵原型
Object.create
根据指定的原型创建新对象,原型可以是null;Object.getPrototypeOf
获得一个对象的原型;Object.setPrototypeOf
设置一个对象的原型。
早期版本中的类与原型
-
‘类’的定义是一个私有属性[[class]],语言标准为内置类型诸如
Number
、String
、Date
等指定了[[class]]属性,以表示它们的类。语言使用者唯一可以访问[[class]]属性的方式是Object.prototype.toString
-
var o = new Object; var n = new Number; var s = new String; var b = new Boolean; var d = new Date; var arg = function(){ return arguments }(); var r = new RegExp; var f = new Function; var arr = new Array; var e = new Error; console.log([o, n, s, b, d, arg, r, f, arr, e].map(v => Object.prototype.toString.call(v))); //输出 (10) ["[object Object]", "[object Number]", "[object String]", "[object Boolean]", "[object Date]", "[object Arguments]", "[object RegExp]", "[object Function]", "[object Array]", "[object Error]"] 0: "[object Object]" 1: "[object Number]" 2: "[object String]" 3: "[object Boolean]" 4: "[object Date]" 5: "[object Arguments]" 6: "[object RegExp]" 7: "[object Function]" 8: "[object Array]" 9: "[object Error]" length: 10 __proto__: Array(0)
new
运算接受一个构造器 和一组调用参数,实际上做了几件事
- 以构造器的
prototype
属性(注意与私有字段[[prototype]]的区分)为原型,创建新对象 - 将
this
和调用参数传给构造器,执行 - 如果构造器返回的时对象,则返回,否则返回第一步创建的对象
JavaScript
中的对象分类
- 宿主对象(
host Objects
):由JavaScript
宿主环境提供的环境,它们的行为完全由宿主环境决定 - 内置对象(
Built-in Object
):由JavaScript
语言提供的对象- 内置对象(
intrinsic Objects
):由标准规定,随着JavaScript
运行时创建而自动创建的对象实例 - 原生对象(
Native Object
):可以由用户通过Array
、RegExp
等内置构造器或者特殊语法创建的对象 - 普通对象(
Ordinary Objects
):由{}语法、Objects
构造器或者class
关键字定义类创建的对象,它能够被原型继承
- 内置对象(
宿主对象
- 浏览器环境中的宿主,全局对象时
window
,window
上又有很多属性,比如document
,实际上这个全局对象window
上的属性,一部分来自于JavaScript
语言,一部分来自于浏览器环境 - 宿主对象也分为固有的和用户可创建的俩种,比如
document.createElement
就可以创建一些dom
对象,宿主也会提供一些构造器,比如我们可以使用new Image
来创建img
对象
内置对象-固有对象
- 固有对象是由标准规定,随着
JavaScript
运行时创建而自动创建的对象实例,固有对象在任何JS
代码执行前就已经被创建出来了。
内置对象-原生对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5EcAR0pB-1581861071709)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200123193705440.png)]
- 通过这些构造器,我们可以用
new
运算创建薪得对象,所以我们把这些对象称作为原生对象 - 这些构造器创建的对象多数使用了私有字段,例如:
Error: [[ErrorData]]
Boolean: [[BooleanData]]
Number: [[NumberData]]
Date: [[DateValue]]
RegExp: [[RegExpMatcher]]
Symbol: [[SymbolData]]
Map: [[MapData]]
用对象来模拟函数与构造器:函数对象与构造器对象
- 函数对象的定义是:具有[[call]]私有字段的对象,构造器对象的定义是:具有私有字段[[construct]]的对象