IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> JavaScript高级程序设计 学习笔记5 - 基本引用类型 -> 正文阅读

[JavaScript知识库]JavaScript高级程序设计 学习笔记5 - 基本引用类型

内容均摘自JavaScript高级程序设计第四版,仅用于记录学习过程。


一. 理解引用类型

5.1 理解引用类型

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

  • 在ECMAScript 中,引用类型是把数据和功能组织到一起的结构
  • 常被人错误地称""
  • 引用类型有时也被称为对象定义,因为它们描述了自己的对象应有的属性和方法

新对象通过使用new操作符后跟一个构造函数来创建,构造函数就是用来创建新对象的函数,比如下面这行代码:

let now = new Date();
  • 创建了引用类型Date的一个新实例,并将它保存在变量now
  • Date()是构造函数,负责创建一个只有默认属性和方法的简单对象

二. Date

5.2 Date

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

创建日期对象,使用new操作符来调用Date构造函数:

let now = new Date();
  • 不给Date构造函数传参数的情况下,创建的对象将保存当前日期和时间
  • 若要基于其他日期和时间创建日期对象,必须传入其毫秒表示,ECMAScript 为此提供了两个辅助方法:Date.parse()Date.UTC()

Date.parse()

Date.parse() :接收一个表示日期的字符串参数,尝试将这个字符串转换为表示该日期的毫秒数

  • 支持的日期格式:
    • “月/日/年”,如"5/23/2021"
    • “月名 日,年”,如"May 23,2021"
    • “周几 月名 日 年 时:分:秒 时区”,如"Tue May 23 2021 00:00:00 GMT-0700"

若直接把表示日期的字符串传给Date()Date会在后台调用Date.parse()

比如,要创建一个表示"2021年5月23日"的日期对象,可以使用以下代码:

let date = new Date(Date.parse("5/23/2021"));
// 等效于
let date = new Date("5/23/2021");

??:若传的字符串不表示日期,则Date.parse()返回NaN


Date.UTC()

Date.UTC()也是返回日期的毫秒数

  • 参数:年、月(以0为起点)、日(1~31)、时(0~23)、分、秒、毫秒
    (只有年和月是必需的,日不提供则默认为1,其他不提供则默认为0)

Date.UTC() 也会被Date()隐式调用,但隐式调用下创建的是本地日期,不是GMT日期

下面是两个例子:

// GMT时间 2000年 1月 1日 0点
let date = new Date(Date.UTC(2000, 0));

// 等效于
// 本地时间 2000年 1月 1日 0点
let date = new Date(2000, 0);
// GMT时间 2021年 8月 1日 5点 55分 55秒
// 注意这里的月不是8,是7,以0为起点
let date = new Date(Date.UTC(2021, 7, 1, 5, 55, 55));

Date.now()

返回表示方法执行时的日期和时间的毫秒数
这个方法可以用在代码分析中:

// 起始时间
let start = Date.now();

// 调用函数
doSomething();

// 结束时间
let stop = Date.now();

// 计算用时
result = stop - start;

5.2.1 继承的方法

与其他引用类型一样,Date重写了toLocaleString()toString()valueOf()方法

  • toLocaleString():返回与浏览器运行的本地环境一致的日期和时间,格式中包含AM(上午)PM(下午),但不包含时区信息,具体格式可能因浏览器而不同
  • toString():返回带时区信息的日期和时间

下面给出这两种方法返回的示例:
2021年8月2日零点

// toLocalString()
8/2/2021 12:00:00 AM
// toString()
Mon Aug 2 2021 00:00:00 GMT-0800 (Pacific Standard Time)
  • valueOf():返回日期的毫秒表示
let date1 = new Date(2021, 0, 1); // 1月1日
let date2 = new Date(2021, 1, 1); // 2月1日

console.log(date1 < date2); // true

5.2.2 日期格式化方法

  • toDateString():显示日期中的周几、月、日、年(格式特定于实现)
  • toTimeString():显示日期中的时、分、秒、时区(格式特定于实现)
  • toLocalDateString():显示日期中的周几、月、日、年(格式特定于实现和地区)
  • toLocaleTimeString():显示时期中的时、分、秒(格式特定于实现和地区)
  • toUTCString():显示完整的UTC日期(格式特定于实现)

这些方法的输出会因浏览器而异,因此不能用于在用户界面上一致地显示日期。


5.2.3 日期/时间组件方法

Date引用类型的其他方法涉及取得设置日期值的特定部分
??:UTC日期指的是没有时区偏移(将日期转换为GMT)时的日期
在这里插入图片描述在这里插入图片描述


三. RegExp

5.3 RegExp

ECMAScript 通过 RegExp 类型支持正则表达式
正则表达式的创建:

let expression = /pattern/flags;

pattern(模式)可以是任何正则表达式,包括字符类、限定符、分组、向前查找、反向引用
每个正则表达式可以不带或带多个flags(标记),用于控制正则表达式的行为

匹配模式的标记:

  • g:全局模式,查找字符串的全部内容,而不是找到第一个匹配的内容就结束
  • I:不区分大小写,查找匹配时忽略大小写
  • m:多行模式,查找到一行文本末尾时会继续查找
  • y:粘附模式,只查找从lastIndex开始及之后的字符串
  • u:Unicode模式,启用 Unicode 匹配
  • s:dotAll模式,匹配任何字符,包括\n\r
// 匹配字符串中的所有"at"
let p1 = /at/g;
// 匹配第一个"bat"或"cat",武略大小写
let p2 = /[bc]at/i;

元字符在模式中必须转义,因为元字符在正则表达式中都有多种特殊功能,所以要匹配这些字符本身就必须使用反斜杠来转义
包括:

() [] {} \ ^ $ | ? * + .
// 匹配第一个"[bc]at",忽略大小写
let p1 = /\[bc\]at/i;
// 匹配所有的".at",忽略大小写
let p2 = /\.at/gi;

上面例子中的正则表达式都是使用字面量形式定义的
也可以使用 RegExp构造函数来创建

  • 接收两个参数:模式字符串和标记字符串
// 匹配第一个"bat"或"cat",忽略大小写
let p = /[bc]at/i;

// 等效于
let p = new RegExp("[bc]at", "i");
  • 因为 RegExp引用类型的模式参数是字符串,所以在某些情况下需要二次转义
    在这里插入图片描述
  • 使用RegExp也可以基于已有的正则表达式实例,并可选择性地修改它们的标记:
const r1 = /cat/g;
const r2 = new RegExp(r1);
const r3 = new RegExp(r1, "i");

console.log(r2);  // "/cat/g"
console.log(r3);  // "/cat/i"

5.3.1 RegExp实例属性

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

  • global:布尔值,是否设置了g标记
  • ignoreCase:布尔值,是否设置了i标记
  • unicode:布尔值,是否设置了u标记
  • sticky:布尔值,是否设置了y标记
  • multiline:布尔值,是否设置了m标记
  • dotAll:布尔值,是否设置了s标记
  • lastIndex:整数,在源字符串中下一次搜索的开始位置
  • source:正则表达式的字面量字符串,没有开头和结尾的斜杠
  • flags:正则表达式的标记字符串

通过这些属性可以全面了解正则表达式的信息,不过实际开发中用的不多


5.3.2 RegExp 实例方法

exec()

RegExp实例的主要方法是exec(),主要用于配合捕获组使用

  • 只接收一个参数,要作为模式的字符串
  • 如果找到了匹配项,返回包含第一个匹配信息的数组
  • 如果没找到匹配项,返回 null

返回的数组是Array的实例,包含两个额外的属性:indexinput

  • 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 从字符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"

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


全局标记

如果模式设置了全局标记,则每一次调用exex()都会返回一个匹配的信息,若不设置全局标记,无论调用多少次exex(),也只会返回第一个匹配的信息

看下例:

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

上面例中的模式没有设置全局标记,因此调用exex()只会返回第一个匹配项("cat")
??:lastIndex在非全局模式下始终不变
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
...

这次模式设置了全局标记,因此每次调用 exec()都会返回字符串中的下一个匹配项,直到搜索到 字符串末尾
??:lastIndex在全局模式下每次调用exec()都会更新
lastIndex表示在查找字符串中下一次搜索开始的位置)


粘附标记

如果模式设置了粘附标记 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对应的字符是",",找不到匹配项,因此返回null 
// 没找到匹配项,于是将lastIndex设置为0
matches = pattern.exec(text);
console.log(matches);  // null
console.log(pattern.lastIndex);  // 0

// 向前设置lastIndex可以让粘附的模式找到下一个匹配项:
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

test()常用于if语句中:

let text = "000-00-0000";
let pattern = /\d{3}-\d{2}-\d{4}/;

if (pattern.test(text)) {
  console.log("The pattern was matched.");
}

上面的例子中,正则表达式用于测试特定的序列
这个用法常用于验证用户输入,此时我们只在乎输入是否有效,不关心为什么无效

??:
无论正则表达式是怎么创建的,toLocaleString()toString()都返回正则表达式的字面量表示valueOf()方法返回正则表达式本身
比如:

let pattern = new RegExp("\\[bc\\]at", "gi");
console.log(pattern.toString());       // /\[bc\]at/gi
console.log(pattern.toLocaleString()); // /\[bc\]at/gi
console.log(pattern.valueOf());  // /\[bc\]at/gi

在这里插入图片描述

5.3.3 RegExp构造函数属性

RegExp构造函数本身也有几个属性(在其他语言中,这种属性被称为静态属性)
这些属性适用于作用域中的所有正则表达式
并且这些属性可以通过两种不同的方式访问(全名和简写)
在这里插入图片描述

四. 原始值包装类型

5.4 原始值包装类型

ECMAScript 提供了 3 种特殊的引用类型: BooleanNumberString
这些类型具有本章介绍的其他引用类型一样的特点,也具有与各自原始类型对应的特殊行为

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

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

变量s1包含一个字符串,它是一个原始值
第二行在变量s1上调用了substring()方法,把结果保存在变量s2

我们知道,原始值本身不是对象,逻辑上不应该有方法,这是因为后台进行了很多处理,从而实现上述操作。

  • 具体来说,当第二行访问变量s1时,是以读模式访问的,也就是要从内存中读取变量s1保存的值
  • 在以读模式访问字符串的时候,后台都会执行以下3步:
    • 创建一个String类型的实例
    • 调用实例上的特定方法
    • 销毁实例
 // 上面的3步类似于执行以下代码
 let s1 = new String("some text");
 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 属性。

可以显式地使用BooleanNumberString构造函数创建原始值包装对象,确定是必要时再这么做,否则容易让开发者分不清到底它们是原始值还是引用值


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

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

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

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

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

let value = "25";
let num1 = Number(value);	// 调用转型函数
console.log(typeof num1);	// "number"

let num2 = new Number(value);  //.调用原始包装类型的构造函数
console.log(typeof num2);	// "object"

在本例中,变量num1保存的是一个值为25的原始数值,而变量num2保存的是一个Number的实例

不推荐显式创建原始值包装类型实例,虽然它们对于操作原始值的功能很重要


5.4.1 Boolean

Boolean是布尔值的引用类型
要创建一个Boolean对象,使用Boolean(),并传入 truefalse,如下例所示:

let booleanObj = new Boolean(true);

在布尔表达式中使用Boolean对象

Boolean 对象在布尔表达式中使用时容易引起误会,用得很少:

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

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

在本例中,第2行对falseObjtrue进行布尔运算,但这个运算是对falseObj对象,而不是对它表示的值false求值,这里就要??:所有对象在布尔表达式中都会自动转换为true
所以true && true当然也为true

原始布尔值和布尔对象的区别

原始值和引用值(Boolean对象)还有一些区别:

  • typeof操作符对原始值返回"boolean",对引用值返回object
  • instanceof操作符对原始值返回false,对引用值返回true
console.log(falseObj instanceof Boolean); // true
console.log(falseVal instanceof Boolean); // false

理解原始布尔值Boolean对象的区别很重要
强烈建议永远不要使用Boolean对象


5.4.2 Number

Number是数值的引用类型
要创建一个Number对象,使用Number(),并传入 一个数值,如下例所示:

let numberObj = new Number(10);

Number引用类型重写了valueOf()toLocaleString()toString()

  • valueOf()返回Number对象表示的原始数值
  • toLocaleString()toString()返回数值字符串
  • toString()可以接收一个表示基数的参数
let num = 10;
console.log(num.toString());  // "10"
console.log(num.toString(2));  // "1010"
console.log(num.toString(16));  // "a"

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

  • toFixed():返回包含指定小数点位数的数值字符串,此方法会自动四舍五入
let num = 10;
console.log(num.toFixed(2));  // "10.00"
  • toExponential():返回以科学计数法表示的数值字符串
let num = 10;
console.log(num.toExponential(1));  // "1.0e+1"
console.log(num.toExponential(3));  // "1.000e+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位数字表示9999不能只用1位数字来精确表示,所以这个方法将它舍入为100
本质上,toPrecision()方法会根据数值精度来决定调用 toFixed() 还是 toExponential()


原始数值和数值对象的区别

  • typeof操作符对原始值返回"number",对引用值返回object
  • instanceof操作符对原始值返回false,对引用值返回true
let numObj = new Number(10);
let numVal = 10;
console.log(numObj instanceof Number); // true
console.log(numVal instanceof Number); // false

理解原始数值Number对象的区别很重要
同样建议不要使用Number对象


isInteger()方法与安全整数

ES6新增了Number.isInteger()方法,用于辨别一个数值是否保存为整数

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

Number.MIN_SAFE_INTERGER(-253 + 1)到Number.MAX_SAFE_INTERGER(253 - 1)范围内,二进制值可以表示为一个整数
超出此范围的数值,即使尝试保存为整数,IEEE 754 编码格式也意味着二进制值可能会表示一个完全不同的数值
可以使用Number.isSageInteger()鉴别整数是否在这个范围内

console.log(Number.isSafeInteger(-1 * (2 ** 53)));      // false
console.log(Number.isSafeInteger(-1 * (2 ** 53) + 1));  // true

5.4.3 String

String是字符串的引用类型
要创建一个String对象,使用String(),并传入 一个字符串,如下例所示:

let stringObj = new String("hello world");

String对象的方法可以在所有的字符串原始值上调用,3个继承的方法valueOf()toLocaleString()toString()都返回对象的原始字符串值

length属性表示字符串中字符的数量,需要??:即使字符串中包含双字节字符,也仍然会按单字符来计数

String类型提供了很多方法来解析和操作字符串:


JavaScript 字符

字符串由16位码元组成,对多数字符来说,每16位码元对应1个字符。

  • 也就是说length属性表示字符串包含多少16位码元
let message = "abc";
console.log(message.length);  // 3
  • charAt()方法返回给定索引位置的字符,具体来说,这个方法查找指定索引位置的16位码元,并返回该码元对应的字符:
let message = "abc";
console.log(message.charAt(2));  // "c"

拼接字符串方法 concat()

  • concat():用于将一个或多个字符串拼接成一个新字符串
let stringVal = "hello ";
let result = stringVal.concat("world");

console.log(result);      // "hello world"
console.log(stringValue); // "hello"

??:stringVal的值是不变的
concat()也可以接收任意多个参数,可以一次性拼接多个字符串:

let stringVal = "hello ";
let result = stringVal.concat("world","!","hahaha");

console.log(result);  // "hello world!hahaha"

(但更常用的还是+拼接多个字符串)


提取子字符串的方法 slice()、substr()、substring()

slice()substr()substring()都会返回调用它们的字符串的一个子字符串,都接收1或2个参数,都不会修改原字符串

  • 第一个参数:表示子字符串开始的位置
  • 第二个参数
    • slice()substring()而言,表示提取结束的位置(该位置之前的字符会被提取)
    • substr()而言,表示提取的子字符串的长度

(若省略第二个参数,默认提取到字符串末尾
??:接收两个参数时,以较小的那个参数作为起点,较大的参数作为终点

let stringVal = "hello world";

console.log(stringVal.slice(3));  // "lo world"
console.log(stringVal.slice(3,7));  // "lo w"  下标7字符之前,下标3字符之后的字符
console.log(stringVal.substring(3,7));  // "lo w"  
console.log(stringVal.substr(3,7));  // "lo worl" 要返回的子字符串长度为7,从下标3字符开始提取

当某个参数负数时:

  • slice():将所有负数参数都当成字符串长度+负数值
let stringVal = "hello world";
console.log(stringVal.slice(-3));  // "rld" -3参数会被转换为长度11+(-3)=8 
console.log(stringVal.slice(3, -4));  // "lo w" -4参数会被转换为长度11+(-4)=7,相当于slice(3,7)
  • substring():将所有负数参数都当成0
let stringVal = "hello world";
console.log(stringVal.substring(-3));  // "hello world" -3参数会被转换为0
console.log(stringVal.substring(3, -4));  // "hel" -4参数会被转换为0,相当于substring(3,0),这又等价于substring(0,3)
  • substr():将第个负参数值当成字符串长度+此值,第个负参数值当成0
let stringVal = "hello world";
console.log(stringVal.substr(-3));  // "rld" -3参数会被转换成长度11+(-3)=8
console.log(stringVal.substr(3, -4));  // "" 空字符串,因为-4参数被转换成0,也就是提取的字符串长度为0

定位子字符串位置的方法 indexOf() 、lastIndexOf()

indexOf()lastIndexOf()从字符串中搜索传入的字符串,并返回位置
(如果没找到,则返回-1)
区别在于:

  • indexOf()从字符串开头开始查找子字符串
  • lastIndexOf()从字符串末尾开始查找子字符串
let stringVal = "hello world";
console.log(stringVal.indexOf("o"));  // 4
console.log(stringVal.lastIndexOf("o"));  // 7

indexOf()lastIndexOf()都接收可选的第二个参数,表示开始搜索的位置
像这样使用第二个参数并循环调用 indexOf()lastIndexOf(),可以在字符串中找到所有的目标子字符串,如下所示:

let stringVal = "Pain makes us stronger";
let positions = [];
let pos = stringVal.indexOf("s");

while(pos != -1) {
  positions.push(pos);
  pos = stringVal.indexOf("s", pos+1);
}

console.log(positions);  // [9,12,14]

本例中,首先取得第一个 "s"的位置,然后进入循环,将上一次的位置+1再传给indexOf()
将每一个"s"的位置都保存在positions数组中


包含字符串的方法 startsWith()、endsWith()、includes()

ES6新增了3个用于判断字符串中是否包含另一个字符串的方法:
这些方法都会从字符串中搜索传入的字符串,并返回一个表示是否包含布尔值
区别在于:

  • startsWith():检查开始于索引0的匹配项
  • endsWith():检查开始于索引string.length - substring.length的匹配项
  • 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
  • startsWith()includes()接收可选的第二个参数,表示开始搜索的位置,这两方法会从指定位置向字符串末尾搜索,忽略该位置前的所有字符
  • endsWith()接收可选的第二个参数,表示应该当作字符串末尾的位置
let message = "foobarbaz";
console.log(message.endsWith("bar", 6));  // true

trim() 方法

trim()方法会创建字符串的一个副本,删除前后所有空格符,再返回结果

let stringVal = "  hello world  ";
let trimmedStringVal = stringVal.trim();
console.log(stringVal);  // "  hello world  "
console.log(trimmedStringVal);  // "hello world"

还有trimLeft():从字符串开始清理空格符
trimRight():从字符串末尾清理空格符


repeat() 方法

repeat()接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果

let stringVal = "ha ";
console.log(stringVal.repeat(5));  // "ha ha ha ha ha "

padStart() 和 padEnd() 方法

padStart()padEnd()复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件
这两个方法接收两个参数

  • 第一个参数是长度
  • 第二个参数是可选的填充字符,默认为空格
let stringVal = "foo";
console.log(stringVal.padStart(6));  // "   foo"
console.log(stringVal.padStart(9,"!"));  // "!!!!!!foo"
console.log(stringVal.padEnd(9,"!"));  // "foo!!!!!!" 

第二个参数并不限于一个字符,可提供多个字符的字符串,则会将其拼接截断匹配指定长度
如果长度小于等于字符串长度,则会返回原始字符串

let stringVal = "foo";
console.log(stringVal.padStart(8, "bar"));  // "barbafoo"
console.log(stringVal.padStart(2));  // "foo"

字符串迭代与解构

字符串的原型上暴露了一个@@iterator方法,表示可以迭代字符串的每个字符
可以像下面这样手动使用迭代器

let message = "abc";
let stringIterator = message[Symbol.iterator]();

console.log(stringIterator.next());  // {value: "a", done: false} 
console.log(stringIterator.next());  // {value: "b", done: false} 
console.log(stringIterator.next());  // {value: "c", done: false} 
console.log(stringIterator.next());  // {value: undefined, done: true}

for-of 循环中可以通过这个迭代器􏰁访问每个字符:

for (const letter of "abc") {
  console.log(letter);
}
// a
// b
// c

有了这个迭代器之后,字符串就可以通过解构操作符来解构了,比如更方便地把字符串分割为字符数组:

let message = "abc";
console.log([...message]); // ["a", "b", "c"]

字符串大小写转换

toLowerCase()
toLocaleLowerCase()
toUpperCase()
toLocaleUpperCase()

let stringValue = "hello world";

console.log(stringValue.toLocaleUpperCase());  // "HELLO WORLD" 
console.log(stringValue.toUpperCase());  // "HELLO WORLD" 
console.log(stringValue.toLocaleLowerCase());  // "hello world" 
console.log(stringValue.toLowerCase());  // "hello world"

toLocaleLowerCase()toLocaleUpperCase()方法旨在基于特定地区实现
在很多地区,地区特定的方法与通用的方法是一样的。但在少数语言中(如土耳其语),要使用地区特定的方法才能实现正确转换


字符串模式匹配方法

String类型为在字符串中实现模式匹配提供了几个方法

  • match():本质上跟RegExp对象的exec()方法相同
    • match()方法接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp对象
let text = "cat, bat, sat, fat";
let pattern = /.at/;

let matches = text.match(pattern); console.log(matches.index); // 0 
console.log(matches[0]); // "cat" 
console.log(pattern.lastIndex); // 0

match()返回的数组exec() 返回的数组是一样的:第个元素是与整个模式匹配字符串,其余元素则是与表达式中的捕获组匹配的字符串(如果有的话)

  • search():接收唯一的参数,可以是一个正则表达式字符串,也可以是一个RegExp对象
    • 返回模式第一个匹配的位置索引,没找到返回-1
    • search()始终从字符串开头向后匹配模式
let text = "cat, bat, sat, fat";
let pos = text.search(/at/);
console.log(pos);  // 1 即"at"的第一个字符在字符串中的位置
replace()

为简化子字符串替换操作,ECMAScript 提供了 replace()方法

  • 接收两个参数
  • 第一个参数可以是一个RegExp 对象或一个字符串(这个字符串不会转换为正则表达式)
  • 第二个参数可以是一个字符串一个函数
let text = "cat, bat, sat, fat";
let result = text.replace("at", "ond");

console.log(result);  // "cond, bat, sat, fat"

如果第个参数是字符串,那只会替换第一个子字符串
要想替换所有子字符串,第个参数必须为正则表达式并且带全局标记

let text = "cat, bat, sat, fat";
let result = text.replace(/at/g, "ond");

console.log(result); // "cond, bond, sond, fond"
split()

最后一个与模式匹配相关的字符串方法是 split()
这个方法会根据传入的分隔符将字符串分成数组

  • 接收两个参数
  • 第一个参数作为分隔符,可以是字符串,也可以是RegExp对象
  • 第二个可选参数是数组的大小,确保返回的数组不会超过指定大小
let colorTxt = "red, blue, green";
let color1 = colorTxt.split(",");  // ["red", "blue", "green"]
let color2 = colorTxt.split(",", 2);  // ["red", "blue"] 这里限制了数组长度为2

localeCompare()

localeCompare()比较两个字符串,返回如下3个值中的一个

  • 如果按照字母表顺序,字符串应该排在字符串参数前面,则返回负值(通常是-1)
  • 如果字符串与字符串参数相等,则返回 0
  • 如果按照字母表顺序􏰁,字符串应该排在字符串参数后面,则返回正值(通常是1)
let stringValue = "yellow";
console.log(stringValue.localeCompare("brick"));  // 1
console.log(stringValue.localeCompare("yellow")); // 0
console.log(stringValue.localeCompare("zoo"));    // -1

"brick"按字母表顺序􏰁应该排在"yellow"前头,因此localeCompare() 返回 1


五. 单例内置对象

5.5 单例内置对象

ECMA-262 对内置对象的定义是:
“任何由 ECMAScript 实现提供、与宿主环境无关,并在 ECMAScript 程序开始执行时存在的对象”
这意味着:开发者不用显式地实例化内置对象,因为它们已经实例化好了

前面我们已经解除了大部分内置对象,包括ObjectArrayString
这里要介绍另外两个单例内置对象:GlobalMath

5.5.1 Global

Global对象最特别,因为代码不会显式地访问它
全局作用域中定义的变量和函数都会变成Global对象的属性,前面介绍的函数包括isNaN()isFinite()parseInt()等,实际上都是Global对象的方法

Global 对象上还有一些其他方法:

URL编码方法

encodeURI()encodeURIComponent()
用于编码统一资源标识符(URI),以传给浏览器

有效的URI不能包含某些字符,比如空格

  • encodeURI():对整个URI进行编码,比如"www.wrox.com/illegal value.js"
  • encodeURIComponent():对URI单独的组件进行编码,比如前面URL中的"illegal value.js"

区别在于:

  • encodeURI()不会编码属于URL组件的特殊字符,比如冒号斜杠问号并号
  • encodeURIComponent()会编码它发现的所有非标准字符
let uri = "http://www.wrox.com/illegal value.js#start";

console.log(encodeURI(uri));
// "http://www.wrox.com/illegal%20value.js#start"

console.log(encodeURIComponent(uri));
// "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.js%23start" 

本例中,使用encodeURI()编码,只有空格被替换为%20,而使用encodeURIComponent()编码,所有非字母字符都替换成了相应的编码形式

encodeURI()encodeURIComponent() 相对的是 decodeURI()decodeURIComponent()

  • decodeURI() 只对使用 encodeURI() 编码过的字符解码
  • decodeURIComponent()解码所有被 encodeURIComponent() 编码的字符,基本上就是解码所有特殊值

eval()

eval()是一个完整的ECMAScript 解释器
接收一个参数,即要执行的JavaScript字符串

eval("console.log('hi')");
// 等效于
console.log('hi');

解释器发现 eval() 调用时,会将参数解释为实际的 ECMAScript 语句,然后将其插入到该位置

Global 对象属性

在这里插入图片描述在这里插入图片描述

获取Global对象

  • 通过window对象,
    浏览器将window对象实现为Global对象的代理,因此所有全局作用域中声明的变量和函数都变成了window的属性
  • 另一种获取Global对象的方式:
let global = function() {
  return this;
}();

这段代码创建了一个立即调用的函数,返回了this的值
当一个函数在没有明确成为某个对象的方法,或通过call() / apply() 指定this值的情况下执行的时候,this值就是Global对象


5.5.2 Math

Math对象的属性

在这里插入图片描述

min() 和 max()

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

舍入方法

把小数值舍入为整数:

  • Math.ceil():始终向舍入为最接近整数
  • Math.floor():始终向舍入为最接近整数
  • Math.round():四舍五入
  • Math.fround():返回数值最接近的单精度(32 位)浮点值表示

random() 方法

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

可以基于如下公式使用 Math.random()从一组整数中随机选择一个数:

number = Math.floor(Math.random() * totalNumber + minVal)

totalNumber为可选的总数,minVal为最小的可能值
这里使用了 Math.floor() 方法,因为 Math.random() 始终返回小数

因此,如果想从1~10范围内随机选择一个数:
可选的总数有10个值,最小的可能值为1

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

其他方法

在这里插入图片描述


六. 小结

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

  • 引用类型相似,但实现不同
  • Date引用类型提供关于日期和时间的信息
  • RegExp引用类型是支持正则表达式的接口

js比较独特的一点是:函数实际上是 Function类型的实例,也就是说函数也是对象。因
为函数也是对象,所以函数也有方法,可以用于增强其能力。

由于原始值包装类型,js中的原始值可以被当成对象使用,有3种原始值包装类型

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

当代码开始执行时,全局上下文中会存在两个内置对象: GlobalMath

  • Global对象无法直接访问,但浏览器将其实现为window对象,所有全局变量和函数都是Global对象的属性
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-04 11:06:48  更:2021-08-04 11:07:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 19:05:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码