JavaScript 中的引用类型Date 和RegExp的详细介绍
作者: 方木头
引用类型 & 引用值的理解
引用值(或者对象)是某个特定引用类型的实例。 在ECMAScript中,引用类型是把数据和功能组织到一起的结构,经常被人错误的称作“类”。虽然从技术上讲JavaScript 是一门面向对象语言,但ECMAScrtipt 缺少传统的面相对象语言所具备的某些基本结构,包括类和接口。引用类型有时候也被称为对象定义,因为它们描述了自己的对象应有的属性和方法。
对象被认为是某个特定引用类型的实例。新对象通过使用new 操作符后跟一个构造函数来创建。构造函数就是用来创建新对象的函数。
let now = new Date();
这行代码代码创建了引用对象Date 的一个新实例,并将它保存在变量now 中。Date()在这里就是构造函数,它负责创建一个只有默认属性和方法的简单对象。ECMAScript 提供了很多像Date这样的原生引用类型,帮助开发者实现常见的任务。函数也是一种引用类型。
Date 引用类型
ECMAScript 的Date 类型参考了Java 早期版本中的java.until.Date.为此,Date类型将日期保存为自协调世界时(UTC)时间1970年1月1日午夜(零时)至今所经过的毫秒数。使用这种存储方式,Date类型可以精确的标识1970年1月1日之前及之后285616年的日期。
要创建日期对象,就是用new 操作符来调用Date构造函数:
let now = new Date(); console.log(now);// Mon Jul 18 2022 15:36:02 GMT+0800 (中国标准时间)
在不给Date 构造函数传递参数的情况下,创建的对象,保存的是当前的日期和时间。要基于其他日期和时间创建日期对象,必须穿入其毫秒标识。ECMAScript 为此提供了两个辅助方法:Date.parse()和Date.UTC();
Date.parse()方法
Date.parse()方法接收一个表示日期和的字符串函数,尝试将这个字符串转换为表示该日期的毫秒数。 ECMA-262 第5版 定义了Date.parse()应该支持的日期格式。所有实现必须支持一下列日期格式:
- “月/日/年”,如“5/23/2022”
- “月名 日,年”,如“May 23,2022”;
- “周几,月名 日 年 时:分:秒”,如”Tue May 23 2019 00:00:00 GMT-0700“。
如果传给Date.parse()的字符串并不表示日期,则该方法返回NaN。如果直接把表示日期的字符串传给Date的构造函数,那么Date 会在后台调用Date.parse()。换句话说,如下两行代码代表的意思一致。
let someDate = new Date(Date.parse("May 23,2022")); let someDateTwo = new Date("May 23,2022");
Date.UTC()方法
Date.UTC()方法也返回日期的毫秒标识,但使用的是跟Date.parse()不同的信息来生成这个值。传给Date.UTC()的参数时年,零起点月数(1月是0,2月是1,依次类推),日(1-31),时(0-23),分,秒和毫秒。这些参数中,只有(年和月)是必须的。如果不提供日,那么默认为1日。其他的默认值都是0.
let y2k = new Date(Date.UTC(2000,0)); //GMT 时间2000年1月1日零点。 let allLives = new Date(Date.UTC(2005,3,5,17,55,55));// 2005年5月5日下午5点55分55秒
与Date.parse()一样,Date.UTC也会被Date的构造函数隐式调用,但有一个区别,这种情况下创建的时本地日期,不是GMT日期。 也就是说,隐式调用情况下下,我们传递给Date.UTC()方法的返回的毫秒数是本地时间距离1970年1月1日的毫秒数,我们传递的这个日期,在JavaScript看来是UTC时间,它默认已经加上了时区插值的毫秒数。但是显示的调用UTC()方法时,传递的日期就是GMT时间。GMT 时间与UTC 时间的关系为:GMT = UTC + 0.
let utc = new Date(2022, 6, 18, 17, 15);// console.log(utc.toString());//Mon Jul 18 2022 17:15:00 GMT+0800 (中国标准时间) console.log(new Date(Date.UTC(2022, 6, 18, 17, 15)));//Tue Jul 19 2022 01:15:00 GMT+0800 (中国标准时间)
Date.parse()方法 与Date.UTC()方法 的使用注意 首先parse方法和UTC 方法都可以隐式调用。所以我们可以这么理解,有两种方式可以创建日期。给Date构造函数传入的是一个日期字符串时,会默认调用parse方法,传入以整数的形式表示的日期会调用UTC方法。但是默认情况下我们传递的日期是加上了时区的毫秒数的,这个一定要清楚。 如果要使用UTC方法的传递GMT时间,一定要显示的调用UTC()方法。
当要明确的求取某个时区的某个时间的毫秒时,需要使用parse()方法。
继承的方法
Date 继承自Object 方法,因此也会有toLocaleString,toString()和valueOf方法。
Date 类型重写了这三个方法的实现:
- Date类型的toLocaleString()方法返回与浏览器运行的本地环境一致的时间和日期。这通常意味着格式中包含针对时间的AM(上午)或PM(下午),但不包含时区信息。
- toString()返回带时区信息的日期和时间,时间也是以24小时制表示的。
- Date类型的valueOf方法根本就不返回字符串,这个方法被重写后返回的是日期的毫秒表示。
下面是toLocaleString,toString()和valueOf的测试打印数据,可供参考。
Date(2022, 6, 14, 10, 50)
toString: Thu Jul 14 2022 10:50:00 GMT+0800 (中国标准时间)
toLocaleString: 2022/7/14 10:50:00
valueOf: 1657767000000****************************
Date.UTC(2022, 6, 14, 10, 50)
toString: Thu Jul 14 2022 18:50:00 GMT+0800 (中国标准时间)
toLocaleString: 2022/7/14 18:50:00
valueOf: 1657795800000****************************
Date.parse("Thur 07 14 2022 10:50:00 GMT+0800")
toString: Thu Jul 14 2022 10:50:00 GMT+0800 (中国标准时间)
toLocaleString: 2022/7/14 10:50:00
valueOf: 1657767000000
****************************
Date("Thur 07 14 2022 10:50:00 GMT+0800")
toString: Thu Jul 14 2022 10:50:00 GMT+0800 (中国标准时间)
toLocaleString: 2022/7/14 10:50:00
valueOf: 1657767000000
****************************
Date.now()
toString: 1657767000086
toLocaleString: 1,657,767,000,086
valueOf: 1657767000086
RegExp
ECMAScript 通过RegExp 类型支持正则表达式。正则表达式使用类似Perl 的简介语法来创建。
let expersiion = /pattern/flags
这个正则表达式的pattern(模式)可以时任何简单或复杂的正则表达式,包括字符类,限定符,分组,向前查找和反向引用。每个正则表达式可以带零个或多个flags(标记),用于控制正则表达式的行为。
下面给出了匹配模式的标记:
- g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。
- i:不区分大小写,表示在查找匹配时忽略pattern和字符串的大小写。
- m:多行模式,表示查找到一行末尾时会继续查找
- y:粘贴模式,表示只查找从lastIndex开始及之后的字符串。
- u:Unicode模式,启用Unicode匹配。
- s:doAll模式,表示元字符,匹配任何字符(包括\n或\r).
使用不同模式和标记可以创建出各种正则表达式,比如:
//匹配字符串中的所有“at” let pattern = /at/g; //匹配第一个“bat”或“cat”,忽略大小写 let pattern2 = /[bc]at/i; //匹配所有以“at”结尾的三字符组合,忽略大小写。 let pattern3 = /.at/gi
与其他语言的正则表达式类似,所有元字符在模式中也必须转义,包括: ( [ \ ^ $ |)] ? * + .
元字符在正则表达式中都有一种或多种特殊功能,所有要匹配上面这些字符本身,就必须使用反斜杠来转义。
//匹配第一个“bat”或“cat”,忽略大小写 let pattern2 = /[bc]at/i; //匹配第一个“[bc]at”,忽略大小写 let pattern2 = /\[bc\]at/i; //匹配所有以“at”结尾的三字符组合,忽略大小写。 let pattern3 = /.at/gi //匹配所有".at",忽略大小写。 let pattern3 = /\.at/gi
前面例子中的正则表达式都是使用字面量形式定义的。正则表达式也可以使用RegExp 构造函数来创建,它接收两个参数:模式字符串和(可选的)标记字符串。任何使用字面量定义的正则表达式也可以通过构造函数来创建:
//匹配第一个“bat”或“cat”,忽略大小写 let pattern1 = /[bc]at/i; //跟pattern1一样,只不过是用构造函数创建的。 let pattern2 = new RegExp("[bc]at","i");
这里的pattern1 和pattern2 是等效的正则表达式。注意,RegExp构造函数的两个参数都是好字符串。因为RegExp的模式参数是字符串,所以某些情况下需要二次转义。所有元字符都必须二次转义,包括转义字符,如\n(\转义后的字符串是\,在正则表达式中则要写成\\).
字面量模式 | 对应的字符串 |
---|---|
/[bc]at/ | "\[bc]\]at" |
/.at/ | "\at." |
/name/age/ | "name\/age" |
/\d/\d{1,2} | "\d.\d{1,2}" |
/\w\hello\123 | "\w\\hello\\123" |
RegExp 实例方法
exec()
RegExp的主要方法是exec(),主要用于配合捕获组使用。这个方法只接受一个参数,即要应用模式的字符串。如果找到了匹配项,则返回包含第一个匹配信息的数组;如果没有找到匹配项,则返回null。返回的数组虽然是Array的实例,。但包含两个额外的属性:index和input。index是字符串中匹配模式的起始位置,input 是要查找的字符串。这个数据的第一个元素是匹配整个模式的字符串,其他元素食欲表达式中的捕获组匹配的字符串。如果模式中没有捕获组,则数组只包含一个元素。
let text = "mom and dad and baby"; let pattern = /mom( and dad( and baby)?)?/gi let matches = pattern.exec(text); console.log(matches.index); //0 console.log(matches.input); //"mom and dad and baby" console.log(matches[0]);// "mom and dad and baby" console.log(matches[1]);// " and dad and baby" console.log(matches[2]);// " and baby"
在这个例子中,模式包含两个捕获组:最内部的匹配项“ and baby”,以及外部的匹配项“ and dad” 或“ and dad and baby”。调用exec()后找到了一个匹配项。因为整个字符串匹配模式,所以matches数组的index 属性就是0。数组的第一个元素是匹配的整个字符串,第二个元素是匹配第一个捕获组的字符串,第三个元素是匹配第二个捕获组的字符串。 如果模式设置了全局标记,则每次调用exec()方法会返回一个匹配的信息。如果没有设置全局标记,则无论对同一个字符串调用多少次exec(),也只会返回第一个匹配的信息。
let text = "cat, bat, sat, fat"; let pattern = /.at/; let matches = pattern.exec(text); console.log(matches.index);//0 console.log(matches[0]);//cat console.log(pattern.lastIndex);//0 matches = pattern.exec(text); console.log(matches.index);//0 console.log(matches[0]);//cat console.log(pattern.lastIndex);//0
上面的例子没有设置全局标记,因此调用exec()只返回第一个匹配项("cat").lastIndex 在非全局模式下始终不变。
如果在这个模式上设置了g标记,则每次调用exec()都会在字符串向前搜索下一个匹配项。
let text = "cat, bat, sat, fat"; let pattern = /.at/g; let matches = pattern.exec(text); console.log(matches.index);//0 console.log(matches[0]);//cat console.log(pattern.lastIndex);//3 matches = pattern.exec(text); console.log(matches.index);//5 console.log(matches[0]);//bat console.log(pattern.lastIndex);//8 matches = pattern.exec(text); console.log(matches.index);//10 console.log(matches[0]);//sat console.log(pattern.lastIndex);//13
如果设置了粘附标记y,则每次调用exec()就只会在lastIndex的位置上寻找匹配项。
粘附标记会覆盖全局标记:
let text = "cat, bat, sat, fat"; let pattern = /.at/y; let matches = pattern.exec(text); console.log(matches.index);//0 console.log(matches[0]);//cat console.log(pattern.lastIndex);//3 //以索引3对应的字符开头找不到匹配项,因此exec() 返回null // matches = pattern.exec(text); console.log(matches);//null console.log(pattern.lastIndex);//0 //向前设置lastIndex 可以让粘附的模式通过exec()找到下一个匹配项。 pattern.lastIndex = 5; matches = pattern.exec(text); console.log(matches.index);//5 console.log(matches[0]);//bat console.log(pattern.lastIndex);//8
test()
正则表达式的另一个方法是test(),接收一个字符串参数。如果输入的文本与模式匹配,则参数返回true,否则返回false。这个方法适用于只想测试模式是否匹配,而不需要世界匹配内容的情况。
let text = "000-00-0000"; let pattern = /\d{3}-\d{2}-\d{4}/; if(pattern.test(test)){ console.log("The pattern was matched."); }
继承的方法
无论正则表达式怎么创建的,继承的方法toLocalString()toString()都返回正则表达式的字面量表示。
let pattern = new RegExp("\\[bc]\\at]at","gi"); console.log(pattern.toString()); ///\[bc\]at/gi console.log(pattern.toLocaleString()); // /\[bc\]at/gi console.log(pattern.valueOf());///\[bc]\at]at/gi
到此这篇关于JavaScript 中的引用类型Date 和RegExp的详细介绍的文章就介绍到这了,更多相关JS引用类型Date和 RegExp内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!