本章节内容多且碎,也都是非常基础的内容,但同时因为其基础,往往容易被忽略,所以本章整理会有较多的细节,内容比较繁琐。
#1 类和对象
ECMAScript 中,引用类型是一种数据结构,用于将数据和功能组织在一起。
(1)类的概念
- 类的实质是一种数据类型,类似于int、char等基本类型,不同的是它是一种复杂的数据类型。
- 本质是类型,而不是数据,不存在于内存中,不能被直接操作,只有被实例化为对象时,才会变得可操作。
ECMAScript 从技术上讲是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基本结构。
(2)类和对象的关系
- 对象是对客观事物的抽象,类是对对象的抽象。
- 对象是类的实例,类是对象的模板。
#2 Object类型
(1)创建方式
有两种创建方式
- 使用
new
操作符后跟Object
构造函数 - 使用字面量表示法。此方法定义对象,实际上不会调用
Object
构造函数(字面量形式的对象默认以Object
为原型对象)
(2)访问对象属性方式
访问一个 Object
类型值的属性,有两种方式:
第一种是,使用点表示法访问对象属性;第二种是,使用方括号表示法访问对象属性,属性名需使用字符串形式,支持变量,可以包含非字母、非数字。
#3 Array类型
(1)创建方式
- 使用
Array
构造函数。参数为非数字或多个数字时,传递的参数作为新数组的元素;参数为单个数字时,表示新数组的长度。 - 使用数组字面量表示法。同样,也不会调用
Array
构造函数。
(2)访问方式
访问的方式非常简单,就是使用方括号访问相应索引的值;但当索引超过现有的项数,也不会报错,数组会自动添加为 undefined
值,此值实际上并不存在。
(3)数组长度
- 通过数组的
length
属性,读取数组的项数; length
属性也可设置数组长度,从数组的末尾移除项或者添加新项(新项值为undefined
);- 设置超过数组长度的项的值,长度会因此改变,中间的空缺项会是
undefined
。
let arr = [1,2,3];
arr[8] = 9;
console.log(arr.length); // 输出10
console.log(arr[7]); //输出 undefined
(4)检测数组
根据前面的内容,我们可能会使用 instanceof
操作符来检测某个对象是不是数组。当网页中包含多个框架时,多个全局环境下可能会存在多个 Array 构造函数,导致出现bug。所以 ES5 中新增 Array.isArray()
方法,适应性更强,推荐使用。
(5)转换方法
toString()
和toLocaleString()
两个方法,都可以返回数组的字符串表示,中间以逗号分隔。特别的是,toLocaleString()
处理日期对象、数字(超过4位)时,会有特定的格式,这跟地区和浏览器有关。(参考博文)valueOf()
方法返回数组本身。jion()
使用指定的分隔符构建字符串。
(6)数组方法
书中提及的数组方法有多种类型,我将它们整理出来,利于记忆,形成一张表格如下
(7)ES5 到 ES8 数组内容
前几天在“前端早读课”公众号中浏览到这部分内容,介绍了从ES5到ES8的关于数组的内容,其中着重介绍了一些方法。我将ES5以后的部分加以整理,贴到这里。
感兴趣可以查看原文章。
#4 Date类型
Date类型数据,使用自UTC时间1970年1月1日0时开始经过的毫秒数来保存。
(1)日期解析
将字符串或数字解析为 Date 类型数据,有两个方法:
Date.parse()
接受常见的日期格式字符串,但不支持中文;不同浏览器支持不同,所以尽量使用标准格式,如:2018/09/20。Date.UTC()
依次接收年份、月份、日、时分秒毫秒参数。注意:月份取0-11,超过11会自动就算增加年份;日期天数是1-31;只能使用24小时时间格式。
(2)构造函数Date
不带 new
操作符使用时,相当于一个函数,返回的是当前日期的字符串;带 new
操作符时,返回的是 Date
类型对象。
let time1 = Date("2018/09/20");
let time2 = new Date("2018/09/20");
console.log(typeof time1); // "string"
console.log(typeof time1); // "object"
给 Date
构造函数提供不同的参数,得到的结果会有差异
- 不提供参数时,使用当前时间和日期创建
Date
对象; - 提供毫秒数时,使用从 GMT(格林威治平均时间)时间 1970年1月1日凌晨到期望日期和时间之间的毫秒来创建
Date
对象; - 提供日期格式字符串,使用特定的表示期望日期和时间的字符串来创建
Date
对象。该字符串的格式应该与Date
对象的parse
方法相匹配; - 数字格式包含( year, month, day, hours, minutes, seconds, milliseconds ),使用年、月、日、小时、分、秒、毫秒的形式创建
Date
对象。格式与 Date 对象的 UTC 方法相匹配。
(3)继承的方法
toLocaleString()
与浏览器设置的地区相适应的格式返回日期和时间,不同浏览器、不同时区格式不一样;toString()
返回带有时区信息的日期和时间;valueOf()
返回日期的毫秒表示。
(4)相关概念
- 格林威治时间/世界时间,Greenwich Mean Time,是指格林威治所在地的标准时间;
- UTC/协调世界时,Coordinated Universal Time,协调世界时是以原子时秒长为基础,在时刻上尽量接近于世界时的一种时间计量系统;
- PST/太平洋标准时间,Pacific Standard Time,加拿大及美国太平洋标准时间,美国西部城市通用的标准时间,以旧金山的时间为准;
- 时间戳,Timestamp,指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
#5 RegExp类型
(1)定义方法
定义 RegExp 类型值的方式有两种,
- 第一种,是正则表达式字面量,也是我们常用的方式;
- 第二种,使用 RegExp 构造函数,接受两个字符串格式的参数,第一个参数是要匹配的字符串模式;第二个参数是标志字符串,即g、i、m中的一个或多个。
(2)RegExp 实例方法
test()
检测字符串中的正则匹配,若匹配返回true
;exec()
最重要的正则方法,检验字符串中的正则匹配,返回存放匹配结果的数组(或null
)。存放匹配结果的数组中,第 0 个元素是与正则表达式相匹配的文本;第 1 个元素是与RegExpObject
第 1 个子表达式相匹配的文本;第 2 个元素是与RegExpObject
第 2 个子表达式相匹配的文本(以此类推);还有index
属性声明的是匹配文本的第一个字符的位置;input
属性则存放的是被检索的字符串;length
属性代表数组长度,此长度不包括index
和input
属性。
如果不是全局模式,每次调用
exec()
返回的都是第一个匹配项;
如果是全局模式,每次调用exec()
返回字符串中的下一个匹配项,直至搜索到字符串末尾为止。
(3)RegExp 构造函数属性
input
最近一次要匹配的字符串lastMatch
最近一次的匹配项lastParen
最近一次匹配的捕获组leftContext
input
字符串中lastMatch
之前的文本multiline
是否所有表达式都使用多行模式rightContext
input
字符串中的lastMatch
之后的文本$1-9
存储捕获组,使用exec()
和test()
方法时,会自动填充,可以直接读取这些值
#6 Function类型
(1)定义方式及其区别
函数的定义方式有三种,他们的区别如下
- 第一种,函数声明,解析器会率先读取函数声明,在执行任何代码之前可用;
- 第二种,函数表达式,必须执行到所在代码行,才会真正被解释执行;
- 第三种,
Function
构造函数,它接受任意数量的参数,最后一个参数是函数体;一般不建议使用这种方法,因为它需要二次解析,影响性能。
(2)函数内部属性
arguments
存放实际传入函数的参数,它的callee
属性指向拥有这个arguments
对象的函数,实际使用中,可以降低代码耦合(比如使用递归时);this
指的是函数执行的环境对象;caller
保存着调用当前函数的函数的引用,如果在全局作用域中调用当前函数,它的值是null
。
(3)函数的属性和方法
length
函数希望接收的命名参数的个数;prototype
保存函数所有实例方法的真正所在,原型相关,后续章节会专门提及;apply() / call()
方法,最关键的作用是扩充函数的作用域;bind()
方法,this
值会被绑定到传给bind()
函数的值;bind
方法创建的是实例,不是执行了该函数;可以通过bind()
传参数,也可以在使用新实例时传参数。
function greetingTo(yourName) {
return `Hello ${yourName}, I'm ${this.name}`;
};
let me = {name: 'Shawn'}, // me 对象中有一个 name 属性
you = 'Tom';
this.name = 'John'; // window 对象中也有一个 name 属性
console.log(greetingTo(you)); // 结果: Hello Tom, I'm John
//没有绑定的情况下,函数运行时 this 指向 window 对象(非严格环境)
console.log(greetingTo.bind(this, you)); // 结果显示的是一个函数表达式: f greetingTo(yourName) { ... }
// bind 方法创建的是实例,不是执行了该函数
console.log(greetingTo.bind(this, you)()); // 结果:Hello Tom, I'm John
// bind 方法绑定 this(即 window 对象) 且执行了该函数(后面的小括号)
// bind 方法绑定同时将参数 you 传递给实例
console.log(greetingTo.bind(me)(you)); // 结果:Hello Tom, I'm Shawn
// bind 方法绑定 me ,实例中的 this 指向 me
// 实例执行的时候再将参数 you 传递给实例
console.log(greetingTo.bind(this, you)('Tony')); // 结果:Hello Tom, I'm John
// bind 方法绑定同时将参数 you 传递给实例
// 实例执行的时候再传递的参数不生效
#7 基本包装类型
使用 new
操作符调用基本类型的构造函数,创建基本包装类型的实例,生成的是一个对象,拥有属性;对基本包装类型的实例调用 typeof
会返回 object
。
不建议显式地创建基本包装类型的对象。
基本包装类型的对象,一般建议使用,正常使用基本类型值即可。我们需要理解的是他们支持的方法。三种类型的继承方法及特殊方法,整理如下表:
补充 String
类型 slice()
、substring()
、substr()
三种方法对于负数参数的处理区别:
#8 单体内置对象
在阮一峰《ECMAScript 6 入门》中提到,在ES5中,顶层对象的属性与全局变量是等价的,全局作用域中声明的所有变量和函数,都会成为 window
对象的属性。
到 ES6 以后,let
命令、const
命令、class
命令声明的全局变量,不属于顶层对象的属性。
顶层对象,在浏览器环境指的是 window 对象,在 Node 指的是 global 对象
以上,就是《Javascript高级程序设计》第五章的学习笔记。
Mark,这章书看的非常疲惫,内容实在太过碎,细读真是一件伤脑筋的事情。。。 o(╥﹏╥)o