笔记:DateRegExp原始值包装类单例内置对象

Posted karshey

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了笔记:DateRegExp原始值包装类单例内置对象相关的知识,希望对你有一定的参考价值。

文章目录

基本引用类型

引用值(或对象)是某个特定引用类型实例
引用类型

  • 是把数据和功能组织到一起的结构,经常被人错误地称作“类”。
  • 也被称为对象定义,因为它们描述了自己的对象应有的属性和方法

对象:

  • 对象被认为是某个特定引用类型的实例
  • 新对象通过使用 new 操作符后跟一个构造函数(constructor)来创建。
  • 构造函数就是用来创建新对象的函数
let now = new Date();

1.Date

Date 类型将日期保存为自 1970 年 1 月 1 日午夜(零时)至今所经过的毫秒数。

创建日期对象

let now = new Date(); 
  • 无参:创建的对象将保存当前日期和时间
  • 有参:传入其毫秒表示(1970 年 1 月 1 日午夜之后的毫秒数)

两个辅助方法

  1. Date.parse()
  2. Date.UTC()

Date.parse()方法:

  • 接收参数:表示日期的字符串
  • 返回:毫秒数(接收的参数不表示日期则返回NaN)

日期格式:

如果直接把表示日期的字符串传给 Date 构造函数,那么 Date 会在后台调用 Date.parse()。

Date.UTC()方法:

  • 参数:年、月(从0开始)、日、时(24时制)、分、秒和毫秒。
  • 返回:日期的毫秒表示
  • 年、月是必须的,其他会默认为0(日默认为1)
  • Date.UTC()会被 Date 构造函数隐式调用,但创建的是本地日期,不是 GMT 日期
  • Date 构造函数跟 Date.UTC()接收的参数是一样的:第一个是年(如果是 数值),第二个是月

还有一个Date.now()方法

  • 返回表示方法执行时日期和时间的毫秒数
  • 可用于代码分析:
// 起始时间
let start = Date.now(); 
// 调用函数
doSomething(); 
// 结束时间
let stop = Date.now(), 
result = stop - start; 

1.1 继承的方法

  • Date 类型重写了 toLocaleString()toString()valueOf()方法
  • 重写后这些方法的返回值不同
  • toLocaleString():返回与浏览器运行的本地环境一致的日期和时间(有AM、PM)
  • toString():返回带时区信息的日期和时间(24时制)
toLocaleString() - 2/1/2019 12:00:00 AM 
toString() - Thu Feb 1 2019 00:00:00 GMT-0800 (Pacific Standard Time) 
  • valueOf():返回的是日期的毫秒表示,操作符(如小于号和大于号)可以直接使用它返回的值

1.2 日期格式化方法

1.3 日期/时间组件方法

太多了,懒得写了,知道一下就行。需要的时候再搜。

2.RegExp正则表达式

语法:

let expression = /pattern/flags;

pattern:模式,要匹配的内容。

flags:匹配模式的标记:

举个例子:

// 匹配字符串中的所有"at" 
let pattern1 = /at/g; 
// 匹配第一个"bat"或"cat",忽略大小写
let pattern2 = /[bc]at/i; 
// 匹配所有以"at"结尾的三字符组合,忽略大小写
let pattern3 = /.at/gi; 

元字符在正则表达式中都有一种或多种特殊功能,所以要匹配上面这些字符本身,就必须使用反斜杠来转义。

( [ \\ ^ $ | ) ] ? * + .

举个对比例子:

// 匹配第一个"bat"或"cat",忽略大小写
let pattern1 = /[bc]at/i; 
// 匹配第一个"[bc]at",忽略大小写
let pattern2 = /\\[bc\\]at/i; 
// 匹配所有以"at"结尾的三字符组合,忽略大小写
let pattern3 = /.at/gi; 
// 匹配所有".at",忽略大小写
let pattern4 = /\\.at/gi; 

正则表达式可以使用 RegExp 构造函数来创建。它接收两个参数(两个参数都是字符串):

  • 模式字符串
  • (可选的)标记字符串
// 匹配第一个"bat"或"cat",忽略大小写
let pattern1 = /[bc]at/i; 
// 跟 pattern1 一样,只不过是用构造函数创建的
let pattern2 = new RegExp("[bc]at", "i"); 

因为要转换为字符串,所有元字符都必须二次转义,包括转义字符序列,如\\n(\\转义后的字符串是\\\\,在正则表达式字符串中则要写成\\\\\\\\)。

举个例子一下看懂:

使用 RegExp 也可以基于已有的正则表达式实例,并可选择性地修改它们的标记:

const re1 = /cat/g; 
console.log(re1); // "/cat/g" 
const re2 = new RegExp(re1); 
console.log(re2); // "/cat/g" 
const re3 = new RegExp(re1, "i"); 
console.log(re3); // "/cat/i" 

2.1 RegExp 实例属性

每个 RegExp 实例都有下列属性:

如:

let pattern1 = /\\[bc\\]at/i; 
console.log(pattern1.source); // "\\[bc\\]at"
let pattern2 = new RegExp("\\\\[bc\\\\]at", "i"); 
console.log(pattern2.source); // "\\[bc\\]at" 

两个\\有一个是转义用的。

2.2 RegExp 实例方法

exec():主要配合捕获组使用。

  • 接收一个参数:要应用模式的字符串
  • 找到:返回包含第一个匹配信息的数组
  • 否则:null
  • 是 Array 的实例
  • 包含两个额外的属性:indexinput
  • index:字符串中匹配模式的起始位置
  • input:要查找的字符串

例子:数组matches的第一个元素是匹配的整个字符串,第二个元素是匹配第一个捕获组的字符串,第三个元素是匹配第二个捕获组的字符串。

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" 

如果在这个模式上设置了 g 标记,则每次调用 exec()都会在字符串中向前搜索下一个匹配项:

  • 模式的 lastIndex 属性每次都会变化
  • 在全局匹配模式下,每次调用 exec()都会更新 lastIndex 值,以反映上次匹配的最后一个字符的索引
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 

2.3 RegExp 构造函数属性

RegExp 构造函数的所有属性都没有任何 Web 标准出处,因此不要在生产环境中使用它们。

RegExp构造函数本身的属性:

  • 在其他语言中,被称为静态属性
  • 适用于作用域中的所有正则表达式
  • 可以用全名或简写(使用中括号语法)访问


举例:

let text = "this has been a short summer"; 
let pattern = /(.)hort/g; 
if (pattern.test(text))  
	 console.log(RegExp.input); // this has been a short summer 
	 console.log(RegExp.leftContext); // this has been a 
	 console.log(RegExp.rightContext); // summer 
	 console.log(RegExp.lastMatch); // short 
	 console.log(RegExp.lastParen); // s 
 

3.原始值包装类型

每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型的对象,从而暴露出操作原始值的各种方法。

如:

let s1 = "some text"; 
let s2 = s1.substring(2); 

其实是:

let s1 = new String("some text"); 
let s2 = s1.substring(2); 
s1 = null; 

步骤:

  1. 创建实例
  2. 调用方法
  3. 销毁实例

引用类型原始值包装类型的主要区别对象的生命周期

  • 通过 new 实例化的对象:离开作用域时被销毁
  • 自动创建的原始值包装对象:只存在于访问它的那行代码执行期间。

举例:

  • 第二行:创建一个String对象,它有属性color=red,在第二行结束后销毁
  • 第三行:创建一个String对象,它没有color,所以会访问到undefined,第三行结束后销毁
let s1 = "some text"; 
s1.color = "red"; 
console.log(s1.color); // undefined 

Object 构造函数:能够根据传入值的类型返回相应原始值包装类型的实例。

  • 如果传给 Object 的是字符串,会创建一个 String 的实例
  • 数值:Number
  • 布尔值: Boolean
let obj = new Object("some text"); 
console.log(obj instanceof String); // true 

使用 new 调用原始值包装类型的构造函数,与调用同名的转型函数不一样:

  • 变量 number:一个值为 25 的原始数值
  • 变量 obj:一个Number 的实例
let value = "25"; 
let number = Number(value); // 转型函数
console.log(typeof number); // "number" 
let obj = new Number(value); // 构造函数
console.log(typeof obj); // "object" 

3.1 Boolean

强烈建议永远不要使用Boolean 对象。

Boolean 是对应布尔值的引用类型。创建Boolean对象如下:

let booleanObject = new Boolean(true); 

Boolean对象使用的很少,因为容易产生误会:所有对象在布尔表达式中都会自动转换为 true。

let falseObject = new Boolean(false); 
let result = falseObject && true; 
console.log(result); // true 

let falseValue = false; 
result = falseValue && true; 
console.log(result); // false 

原始值和引用值(Boolean 对象)的区别:

  • falseObject是Boolean的实例,它的type是object,确实是Boolean的实例(instanceof Boolean返回true)
  • falseValue是原始值,它的type是boolean,它不是Boolean的实例(instanceof Boolean返回false)
console.log(typeof falseObject); // object 
console.log(typeof falseValue); // boolean 
console.log(falseObject instanceof Boolean); // true 
console.log(falseValue instanceof Boolean); // false 

3.2 Number

不建议直接实例化 Number 对象。

Number 是对应数值的引用类型。创建Number对象如下:

let numberObject = new Number(10); 

Number重写的方法:

  • valueOf():返回原始数值
  • toLocaleString()
  • toString():可选地接收一个表示基数的参数,并返回相应基数形式(基数进制)的数值字符串
let num = 10; 
console.log(num.toString()); // "10" 
console.log(num.toString(2)); // "1010" 
console.log(num.toString(8)); // "12" 
console.log(num.toString(10)); // "10" 
console.log(num.toString(16)); // "a" 

Number将数值格式化为字符串的方法:

toFixed()

  • 返回包含指定小数点位数的数值字符串(超出则四舍五入)
  • 多个浮点数值的数学计算不一定得到精确的结果
  • 可以表示有 0~20 个小数位的数值

toExponential()

  • 科学记数法(指数记数法)
  • 接收一个参数,表示结果中小数的位数
let num = 10; 
console.log(num.toExponential(1)); // "1.0e+1" 

toPrecision()

  • 根据情况返回最合理的输出结果,可能是固定长度,也可能是科学记数法形式。
  • 接收一个参数,表示结果中数字的总位数(不包含指数)
  • 本质:根据数值和精度来决定调用 toFixed()还是 toExponential()
  • 会四舍五入(根据参数)
let num = 99; 
console.log(num.toPrecision(1)); // "1e+2" 
console.log(num.toPrecision(2)); // "99" 
console.log(num.toPrecision(3)); // "99.0" 
  • 用 1 位数字表示99,得到"1e+2",即100(99 不能只用 1 位数字来精确表示,则四舍五入为100)
  • 用 2 位数字表示 99 得到"99"
  • 用 3 位数字则是"99.0"

不建议直接实例化 Number 对象。原因:在处理原始数值和引用数值时,typeofinstacnceof操作符会返回不同的结果:

let numberObject = new Number(10); 
let numberValue = 10; 
console.log(typeof numberObject); // "object" 
console.log(typeof numberValue); // "number" 
console.log(numberObject instanceof Number); // true 
console.log(numberValue instanceof Number); // false 

isInteger()方法与安全整数

Number.isInteger()

  • 是否为整数
  • 小数位的0可能会让人误以为数值是一个浮点值

安全整数:

  • Number.MIN_SAFE_INTEGER(-253 +1)到Number.MAX_SAFE_INTEGER(253-1)
  • 判断是否在安全整数范围内:Number.isSafeInteger()

3.3 String

  • String 是对应字符串的引用类型
  • String 对象的方法可以在所有字符串原始值上调用
  • String 类型提供了很多方法来解析和操作字符串

3.3.1 javascript 字符

  • JavaScript 字符串由 16 位码元(code unit)组成
  • 对多数字符来说,每 16 位码元对应一个字符
  • 使用了两种 Unicode 编码混合的策略:UCS-2 和 UTF-16:对于可以采用 16 位编码的字符(U+0000~U+FFFF),这两种编码实际上是一样的

相关方法:

  • charCodeAt():查看指定码元的字符编码
  • fromCharCode():根据给定的 UTF-16 码元创建字符串中的字符

对于 U+0000~U+FFFF 范围内的字符,length、charAt()、charCodeAt()和 fromCharCode()返回的结果都跟预期是一样的。

上述对应关系在扩展到 Unicode 增补字符平面时成立。

Unicode:

  • 基本多语言平面(BMP)
  • 为了表示更多的字符,Unicode 采用了一个策略,即每个字符使用另外 16 位去选择一个增补平面
  • 这种每个字符使用两个 16 位码元的策略称为代理对

举例:

let message = "ab☺de"; 
console.log(message.charAt(2)); // <?> 
console.log(message.charAt(3)); // <?> 
console.log(message.charAt(4)); // d 

console.log(message.charCodeAt(2)); // 55357 
console.log(message.charCodeAt(3)); // 56842 
console.log(message.charCodeAt(4)); // 100 

console.log(String.fromCodePoint(0x1F60A)); // ☺
console.log(String.fromCharCode(97, 98, 55357, 56842, 100, 101)); // ab☺de
  • 上述方法将16位码元当作一个字符
  • 而☺是一个代理对,应该将两个16位码元看作一个字符
  • fromCharCode()可以返回正确的结果:原因是它基于提供的二进制表示直接组合成字符串。浏览器可以直接解析代理对

这里介绍一个新方法:codePointAt()

  • 可以正确解析既包含单码元字符又包含代理对字符的字符串
  • 接收 16 位码元的索引并返回该索引位置上的码点(code point)
  • 码点是 Unicode 中一个字符的完整标识
let message = "ab☺de"; 
console.log(message.codePointAt(1)); // 98 
console.log(message.codePointAt(2)); // 128522 
console.log(message.codePointAt(3)); // 56842 
console.log(message.codePointAt(4)); // 100 

注意:

  • 传入的码元索引要是代理对的开头,否则会返回错误码点
  • 这种错误只有检测单个字符时出现
  • 解决方法:过从左到右按正确的码元数遍历字符串
  • 如:迭代字符串
console.log([..."ab☺de"]); // ["a", "b", "☺", "d", "e"] 

对比:fromCharCodefromCodePoint

console.log(String.fromCharCode(97, 98, 55357, 56842, 100, 101)); 
// ab☺de 
console.log(String.fromCodePoint(97, 98, 128522, 100, 101)); 
// ab☺de 

3.3.2 normalize()方法

某些 Unicode 字符可以有多种编码方式:

  • 通过一个 BMP 字符表示
  • 通过一个代理对表示

举例:Å字符(A上有一个圈)——三个都是

console.log(String.fromCharCode(0x00C5))
console.log(String.fromCharCode(0x212B))
console.log(String.fromCharCode(0x0041, 0x030A))

比较操作符:3个字符互不相等。

为了解决这种问题,Unicode提供了 4种规范化形式:

  • NFD
  • NFC
  • NFKD
  • NFKC

方法:normalize()
参数:规范化形式的字符串。

三个字符选择同一种规范化形式可以让比较操作符返回正确的结果:

let a1 = String.fromCharCode(0x00C5), 
 a2 = String.fromCharCode(0x212B), 
 a3 = String.fromCharCode(0x0041, 0x030A); 

console.log(a1.normalize("NFD") === a2.normalize("NFD")); 
// true 
console.log(a2.normalize("NFKC") === a3.normalize(JS中数据类型原始数据内置对象包装类型对象typeof

静态内部类单例模式

js基本语法

正则表达式工具类单例

如何使 Swift 类单例实例线程安全?

什么是“JS”的内置对象?