【红宝书笔记精简版】第五章 引用类型

目录

注:适合有基础并需要系统复习的同学

5.1 Date 类型

5.1.1 继承的方法

5.1.2 日期格式化方法

5.1.3 日期/时间组件方法

5.2 RegExp 类型

5.2.1 RegExp实例属性

5.2.2 RegExp实例方法

5.2.3 RegExp构造函数属性        

5.2.4 模式的局限性

5.3 原始包装类型

5.3.1 Boolean类型

5.3.2 Number类型

5.3.3 String类型

5.7 单体内置对象

5.7.1 Global对象

5.7.2 Math对象

5.8 小结


注:适合有基础并需要系统复习的同学

5.1 Date 类型

要创建一个日期对象,使用 new 操作符和 Date 构造函数即可:

//取得开始时间
var start = Date.now(); 
//调用函数
doSomething(); 
//取得停止时间
var stop = Date.now(), 
 result = stop – start; 

5.1.1 继承的方法

Date 类型重写了 toLocaleString()、toString()和 valueOf()方法。但与 其他类型不同,重写后这些方法的返回值不一样。Date 类型的 toLocaleString()方法返回与浏览器 运行的本地环境一致的日期和时间。这通常意味着格式中包含针对时间的 AM(上午)或 PM(下午), 但不包含时区信息(具体格式可能因浏览器而不同)。toString()方法通常返回带时区信息的日期和时 间,而时间也是以 24 小时制(0~23)表示的。下面给出了 toLocaleString()和 toString()返回的 2019 年 2 月 1 日零点的示例(地区为"en-US"的 PST,即 Pacific Standard Time,太平洋标准时间): toLocaleString() - 2/1/2019 12:00:00 AM toString() - Thu Feb 1 2019 00:00:00 GMT-0800 (Pacific Standard Time)

5.1.2 日期格式化方法

Date 类型有几个专门用于格式化日期的方法,它们都会返回字符串:
 toDateString()显示日期中的周几、月、日、年(格式特定于实现);
 toTimeString()显示日期中的时、分、秒和时区(格式特定于实现);
 toLocaleDateString()显示日期中的周几、月、日、年(格式特定于实现和地区);
 toLocaleTimeString()显示日期中的时、分、秒(格式特定于实现和地区);
 toUTCString()显示完整的 UTC 日期(格式特定于实现)。
这些方法的输出与 toLocaleString()和 toString()一样,会因浏览器而异。因此不能用于在用户界面上一致地显示日期。

5.1.3 日期/时间组件方法

5.2 RegExp 类型

ECMAScript 通过 RegExp 类型支持正则表达式。正则表达式使用类似 Perl 的简洁语法来创建: let expression = /pattern/flags;
这个正则表达式的 pattern(模式)可以是任何简单或复杂的正则表达式,包括字符类、限定符、 分组、向前查找和反向引用。每个正则表达式可以带零个或多个 flags(标记),用于控制正则表达式 的行为。下面给出了表示匹配模式的标记:
 g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。
 i:不区分大小写,表示在查找匹配时忽略 pattern 和字符串的大小写。
 m:多行模式,表示查找到一行文本末尾时会继续查找。
 y:粘附模式,表示只查找从 lastIndex 开始及之后的字符串。
 u:Unicode 模式,启用 Unicode 匹配。
 s:dotAll 模式,表示元字符.匹配任何字符(包括\n 或\r)。 使用不同模式和标记可以创建出各种正则表达式,比如:

// 匹配字符串中的所有"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;

 任何使用字面量定义的正则表达式也可 以通过构造函数来创建,比如:

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

5.2.1 RegExp实例属性

每个 RegExp 实例都有下列属性,提供有关模式的各方面信息。
 global:布尔值,表示是否设置了 g 标记。
 ignoreCase:布尔值,表示是否设置了 i 标记。
 unicode:布尔值,表示是否设置了 u 标记。
 sticky:布尔值,表示是否设置了 y 标记。
 lastIndex:整数,表示在源字符串中下一次搜索的开始位置,始终从 0 开始。
 multiline:布尔值,表示是否设置了 m 标记。
 dotAll:布尔值,表示是否设置了 s 标记。
 source:正则表达式的字面量字符串(不是传给构造函数的模式字符串),没有开头和结尾的 斜杠。
 flags:正则表达式的标记字符串。始终以字面量而非传入构造函数的字符串模式形式返回(没 有前后斜杠)。

let pattern1 = /\[bc\]at/i;
console.log(pattern1.global); // false
console.log(pattern1.ignoreCase); // true
console.log(pattern1.multiline); // false
console.log(pattern1.lastIndex); // 0
console.log(pattern1.source); // "\[bc\]at"
console.log(pattern1.flags); // "i" 

5.2.2 RegExp实例方法

RegExp 实例的主要方法是 exec(),主要用于配合捕获组使用。这个方法只接收一个参数,即要应 用模式的字符串。如果找到了匹配项,则返回包含第一个匹配信息的数组;如果没找到匹配项,则返回 null。

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
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

正则表达式的另一个方法是 test(),接收一个字符串参数。如果输入的文本与模式匹配,则参数 返回 true,否则返回 false。这个方法适用于只想测试模式是否匹配,而不需要实际匹配内容的情况。

let text = "000-00-0000";
let pattern = /\d{3}-\d{2}-\d{4}/;
if (pattern.test(text)) {
 console.log("The pattern was matched.");
} 

5.2.3 RegExp构造函数属性        

下表列出了 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
} 

if (pattern.test(text)) {
 console.log(RegExp.$_); // this has been a short summer
 console.log(RegExp["$`"]); // this has been a
 console.log(RegExp["$'"]); // summer
 console.log(RegExp["$&"]); // short
 console.log(RegExp["$+"]); // s
} 

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

5.2.4 模式的局限性

下列特性目前还没有得到 ECMAScript 的支持(想要了解更多信息,可以参考 Regular-Expressions.info 网站):
 \A 和\Z 锚(分别匹配字符串的开始和末尾)
 联合及交叉类
 原子组
 x(忽略空格)匹配模式
 条件式匹配
 正则表达式注释      

5.3 原始包装类型

为了方便操作原始值,ECMAScript 提供了 3 种特殊的引用类型:Boolean、Number 和 String。每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型的对象,从而暴露出操作原始值的 各种方法.

// 例:
let s1 = "some text";
let s2 = s1.substring(2);
/**
在这里,s1 是一个包含字符串的变量,它是一个原始值。第二行紧接着在 s1 上调用了 substring()
方法,并把结果保存在 s2 中。我们知道,原始值本身不是对象,因此逻辑上不应该有方法。而实际上
这个例子又确实按照预期运行了。这是因为后台进行了很多处理,从而实现了上述操作
*/

// 可以把这 3 步想象成执行了如下 3 行 ECMAScript 代码:
let s1 = new String("some text"); // 创建一个 String 类型的实例;
let s2 = s1.substring(2); // 调用实例上的特定方法;
s1 = null; // 销毁实例。

引用类型与原始值包装类型的主要区别在于对象的生命周期。在通过 new 实例化引用类型后,得到 的实例会在离开作用域时被销毁,而自动创建的原始值包装对象则只存在于访问它的那行代码执行期 间。这意味着不能在运行时给原始值添加属性和方法。比如下面的例子:

let s1 = "some text";
s1.color = "red";
console.log(s1.color); // undefined
/**
这里的第二行代码尝试给字符串 s1 添加了一个 color 属性。可是,第三行代码访问 color 属性时,
它却不见了。原因就是第二行代码运行时会临时创建一个 String 对象,而当第三行代码执行时,这个对
象已经被销毁了。实际上,第三行代码在这里创建了自己的 String 对象,但这个对象没有 color 属性。
*/

 Object 构造函数作为一个工厂方法,能够根据传入值的类型返回相应原始值包装类型的实例:

let obj = new Object("some text");
console.log(obj instanceof String); // true

let obj2 = new Object(123);
console.log(obj2 instanceof Number); // true

let obj3 = new object(true); 
console.log(obj3 instanceof Boolean) // true

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

let value = "25";
let number = Number(value); // 转型函数
console.log(typeof number); // "number"
let obj = new Number(value); // 构造函数
console.log(typeof obj); // "object"

5.3.1 Boolean类型

Boolean 是对应布尔值的引用类型。要创建一个 Boolean 对象,就使用 Boolean 构造函数并传入 true 或 false,如下例所示:

 Boolean 的实例会重写 valueOf()方法,返回一个原始值 true 或 false。toString()方法被调 用时也会被覆盖,返回字符串"true"或"false".

包装类型Boolean与原始值Boolean的区别:


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

/ **
// 所有对象在布尔表达式中都会自动转换为 true,因此 falseObject 在这个表达式里实际上表示一个 true 值。
*/

typeof 操作符对原始值返回 "boolean",但对引用值返回"object"。同样,Boolean 对象是 Boolean 类型的实例,在使用 instaceof 操作符时返回 true,但对原始值则返回 false,如下所示:

console.log(typeof falseObject); // object
console.log(typeof falseValue); // boolean
console.log(falseObject instanceof Boolean); // true
console.log(falseValue instanceof Boolean); // false

 注:理解原始布尔值和 Boolean 对象之间的区别非常重要,强烈建议永远不要使用后者。

5.3.2 Number类型

Number 是对应数值的引用类型。要创建一个 Number 对象,就使用 Number 构造函数并传入一个 数值,如下例所示:

与 Boolean 类型一样,Number 类型重写了 valueOf()、toLocaleString()和 toString()方 法。valueOf()方法返回 Number 对象表示的原始数值,另外两个方法返回数值字符串。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()方法返回包含指定小数点位数的数值字符串,如:

let num = 10;
console.log(num.toFixed(2)); // "10.00"

toExponential(),返回以科学记数法(也称为指数记数法)表示的数值字符串: 

let num = 10;
console.log(num.toExponential(1)); // "1.0e+1"

toPrecision()方法会根据情况返回最合理的输出结果,可能是固定长度,也可能是科学记数法 形式:

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,这样就可以只用 1 位数字(及其科学记数法形式)
来表示了。用 2 位数字表示 99 得到"99",用 3 位数字则是"99.0"。本质上,toPrecision()方法会
根据数值和精度来决定调用 toFixed()还是 toExponential()。
*/

isInteger()方法与安全整数、Number.isInteger()方法,用于辨别一个数值是否保存为整数:

console.log(Number.isInteger(1)); // true
console.log(Number.isInteger(1.00)); // true
console.log(Number.isInteger(1.01)); // false

 与Boolean包装类型类似:

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 

5.3.3 String类型

部分方法示例:

// 1. chartAt() 
let message = "abcde";
console.log(message.charAt(2)); // "c"

// 2. chartCodeA()
let message = "abcde";
// Unicode "Latin small letter C"的编码是 U+0063
console.log(message.charCodeAt(2)); // 99 

// 3. fromCharCode()
console.log(String.fromCharCode(0x61, 0x62, 0x63, 0x64, 0x65)); // "abcde"

部分字符串操作方法示例:

// 1. concat() 
let stringValue = "hello ";
let result = stringValue.concat("world");
console.log(result); // "hello world"
console.log(stringValue); // "hello"

// 2. slice() 
// substring() 
// substr() 第二个参数表示返回的字符个数
let stringValue = "hello world";
console.log(stringValue.slice(3)); // "lo world"
console.log(stringValue.substring(3)); // "lo world"
console.log(stringValue.substr(3)); // "lo world"
console.log(stringValue.slice(3, 7)); // "lo w"
console.log(stringValue.substring(3,7)); // "lo w"
console.log(stringValue.substr(3, 7)); // "lo worl"

// 3. indexOf()
// lastIndexOf()
let stringValue = "hello world";
console.log(stringValue.indexOf("o")); // 4
console.log(stringValue.lastIndexOf("o")); // 7

// 4.startsWith()
// endsWith()
// includes()

let message = "foobarbaz";
console.log(message.startsWith("foo")); // true
console.log(message.startsWith("bar")); // false
console.log(message.endsWith("baz")); // true
console.log(message.endsWith("bar")); // false
console.log(message.includes("bar")); // true
console.log(message.includes("qux")); // false 

// 5. trim()
let stringValue = " hello world ";
let trimmedStringValue = stringValue.trim();
console.log(stringValue); // " hello world "
console.log(trimmedStringValue); // "hello world"

// 6. repeat()
let stringValue = "na ";
console.log(stringValue.repeat(16) + "batman");
// na na na na na na na na na na na na na na na na batman

// 7. padStart() 
// padEnd()
let stringValue = "foo";
console.log(stringValue.padStart(6)); // " foo"
console.log(stringValue.padStart(9, ".")); // "......foo"
console.log(stringValue.padEnd(6)); // "foo "
console.log(stringValue.padEnd(9, ".")); // "foo......"

5.4 单体内置对象

开发者不用显式地实例化内置对象,因为它们已经实例 化好了。前面我们已经接触了大部分内置对象,包括 Object、Array 和 String。本节介绍 ECMA-262 定义的另外两个单例内置对象:Global 和 Math。

5.4.1 Global对象

Global 对象是 ECMAScript 中最特别的对象,因为代码不会显式地访问它。ECMA-262 规定 Global 对象为一种兜底对象,它所针对的是不属于任何对象的属性和方法。在全局作用域中定义的变量和函数都会变成 Global 对象的属性.包括 isNaN()、isFinite()、parseInt()和 parseFloat(),

Global 对象上还有另外一些方法:

1. URL 编码方法 encodeURI()和 encodeURIComponent()方法用于编码统一资源标识符(URI),以便传给浏览器。有效的 URI 不能包含某些字符,比如空格。使用 URI 编码方法来编码 URI 可以让浏览器能够理解它们, 同时又以特殊的 UTF-8 编码替换掉所有无效字符。

与 encodeURI()和 encodeURIComponent()相对的是 decodeURI()和 decodeURIComponent()。 decodeURI()只对使用 encodeURI()编码过的字符解码。

2. eval()方法

这个方法就是一个完 整的 ECMAScript 解释器,它接收一个参数,即一个要执行的 ECMAScript(JavaScript)字符串。

eval("console.log('hi')");
// 上面这行代码的功能与下一行等价:
console.log("hi");

let msg = "hello world";
eval("console.log(msg)"); // "hello world"

eval("function sayHi() { console.log('hi'); }");
sayHi(); 

// 通过 eval()定义的任何变量和函数都不会被提升,这是因为在解析代码的时候,它们是被包含在
一个字符串中的。它们只是在 eval()执行的时候才会被创建。
eval("let msg = 'hello world';");
console.log(msg); // Reference Error: msg is not defined 

3. Global 对象属性 

4. window 对象

虽然 ECMA-262 没有规定直接访问 Global 对象的方式,但浏览器将 window 对象实现为 Global 对象的代理。因此,所有全局作用域中声明的变量和函数都变成了 window 的属性.

var color = "red";
function sayColor() {
 console.log(window.color);
}
window.sayColor(); // "red"
/**
这里定义了一个名为color的全局变量和一个名为sayColor()的全局函数。在sayColor()内部,
通过 window.color 访问了 color 变量,说明全局变量变成了 window 的属性。接着,又通过 window
对象直接调用了 window.sayColor()函数,从而输出字符串。

*/

获取globel对象的方法:

let global = function() {
 return this;
}(); 

5.4.2 Math对象

1. Math 对象属性

Math 对象有一些属性,主要用于保存数学中的一些特殊值:

2. min()和 max()方法

let max = Math.max(3, 54, 32, 16);
console.log(max); // 54
let min = Math.min(3, 54, 32, 16);
console.log(min); // 3 

let values = [1, 2, 3, 4, 5, 6, 7, 8];
let max = Math.max(...val);

3. 舍入方法

接下来是用于把小数值舍入为整数的 4 个方法:Math.ceil()、Math.floor()、Math.round() 和 Math.fround():

// Math.ceil()方法始终向上舍入为最接近的整数。
console.log(Math.ceil(25.9)); // 26
console.log(Math.ceil(25.5)); // 26
console.log(Math.ceil(25.1)); // 26
// Math.round()方法执行四舍五入
console.log(Math.round(25.9)); // 26
console.log(Math.round(25.5)); // 26
console.log(Math.round(25.1)); // 25
// Math.fround()方法返回数值最接近的单精度(32 位)浮点值表示
console.log(Math.fround(0.4)); // 0.4000000059604645
console.log(Math.fround(0.5)); // 0.5
console.log(Math.fround(25.9)); // 25.899999618530273
// Math.floor()方法始终向下舍入为最接近的整数。
console.log(Math.floor(25.9)); // 25
console.log(Math.floor(25.5)); // 25
console.log(Math.floor(25.1)); // 25

4. random()方法

Math.random()方法返回一个 0~1 范围内的随机数,其中包含 0 但不包含 1。

如果想从 1~10 范围内随机选择一个数:

let num = Math.floor(Math.random() * 10 + 1);

注: Math.random()方法在这里出于演示目的是没有问题的。如果是为了加密而需要 生成随机数(传给生成器的输入需要较高的不确定性),那么建议使用 window.crypto. getRandomValues()。 

5. 其他方法

5.5 小结

JavaScript 中的对象称为引用值,几种内置的引用类型可用于创建特定类型的对象。

  •  引用值与传统面向对象编程语言中的类相似,但实现不同。
  • Date 类型提供关于日期和时间的信息,包括当前日期、时间及相关计算。
  • RegExp 类型是 ECMAScript 支持正则表达式的接口,提供了大多数基础的和部分高级的正则表 达式功能。

JavaScript 比较独特的一点是,函数实际上是 Function 类型的实例,也就是说函数也是对象。因 为函数也是对象,所以函数也有方法,可以用于增强其能力。 由于原始值包装类型的存在,JavaScript 中的原始值可以被当成对象来使用。有 3 种原始值包装类 型:Boolean、Number 和 String。它们都具备如下特点。

  • 每种包装类型都映射到同名的原始类型。
  • 以读模式访问原始值时,后台会实例化一个原始值包装类型的对象,借助这个对象可以操作相 应的数据。
  • 涉及原始值的语句执行完毕后,包装对象就会被销毁。

当代码开始执行时,全局上下文中会存在两个内置对象:Global 和 Math。其中,Global 对象在 大多数 ECMAScript 实现中无法直接访问。不过,浏览器将其实现为 window 对象。所有全局变量和函数都是 Global 对象的属性。Math 对象包含辅助完成复杂计算的属性和方法。

猜你喜欢

转载自blog.csdn.net/weixin_41950078/article/details/120921469