JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记

引用值或者对象,是某个特定引用类型的实例
在 ECMAScript 中,引用类型是把数据和功能组织到一起的结构,经常被人错误地称作“类”,但它不是类。
引用类型有时候也被称为对象定义,因为它们描述了自己的对象应有的属性和方法。

对象被认为是某个特定引用类型的实例。
创建对象:new操作符 + 构造函数(constructor)

let now = new Date();

这行代码创建了引用类型 Date 的一个新实例,并将它保存在变量 now 中。
Date()在这里就是构造函数,它负责创建一个只有默认属性和方法的简单对象。
函数也是一种引用类型。

5.1 Date

Date 类型将日期保存为自协调世界时(UTC,Universal Time Coordinated)时间 1970 年 1 月 1 日午夜(零时)至今所经过的毫秒数。

创建Date对象:

let now = new Date(); 

在不给 Date 构造函数传参数的情况下,创建的对象将保存当前日期和时间。要基于其他日期和时间创建日期对象,必须传入其毫秒表示(UNIX 纪元 1970 年 1 月 1 日午夜之后的毫秒数)。

5.1.1 Date.parse() 方法

接收一个表示日期的字符串参数,尝试将这个字符串转换为表示该日期的毫秒数
支持以下日期格式:

  • “月/日/年”,如"5/23/2019";
  • “月名 日, 年”,如"May 23, 2019";
  • “周几 月名 日 年 时:分:秒 时区”,如"Tue May 23 2019 00:00:00 GMT-0700";
  • ISO 8601 扩展格式“YYYY-MM-DDTHH:mm:ss.sssZ”,如 2019-05-23T00:00:00(只适用于 兼容
    ES5 的实现)。
let someDate = new Date(Date.parse("May 23, 2019")); 
let someDate = new Date("May 23, 2019"); 

这两行得到的日期对象是相同的,因为如果直接把表示日期的字符串传给Date构造函数,那么Date会在后台调用Date.parse()。

如果传给 Date.parse()的字符串并不表示日期,则该方法会返回 NaN。

5.1.2 Date.UTC() 方法

返回日期的毫秒表示
参数:

  • 零起点月数(1 月是 0,2 月是 1,以此类推)
  • 日(1~31)
  • 时(0~23)
  • 毫秒

年和月是必需的。如果不提供日,那么默认为 1 日。其他参数的默认值都是 0。

// GMT 时间 2005 年 5 月 5 日下午 5 点 55 分 55 秒
let allFives = new Date(Date.UTC(2005, 4, 5, 17, 55, 55));
let allFives = new Date(2005, 4, 5, 17, 55, 55);

这两行得到的日期对象是相同的,因为Date.UTC()也会被 Date 构造函数隐式调用,但这次的两个日期是(由于系统设置决定的)本地时区的日期。

5.1.3 Date.now() 方法

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

// 起始时间
let start = Date.now(); 
// 调用函数
doSomething(); 
// 结束时间
let stop = Date.now(), 
result = stop - start; 

5.1.4 继承的方法

与其他类型一样,Date 类型重写了 toLocaleString()、toString()和 valueOf()方法。但与其他类型不同,重写后这些方法的返回值不一样。

toLocaleString()方法返回与浏览器运行的本地环境一致的日期和时间。这通常意味着格式中包含针对时间的 AM(上午)或 PM(下午),但不包含时区信息(具体格式可能因浏览器而不同)。

toString()方法通常返回带时区信息的日期和时间,而时间也是以 24 小时制(0~23)表示的。

现代浏览器在这两个方法的输出上已经趋于一致。在比较老的浏览器上,每个方法返回的结果可能在每个浏览器上都是不同的。这些差异意味着 toLocaleString()和 toString()可能只对调试有用,不能用于显示。

valueOf()方法根本就不返回字符串,这个方法被重写后返回的是日期的毫秒表示。因此,操作符(如小于号和大于号)可以直接使用它返回的值。

let date1 = new Date(2019, 0, 1); // 2019 年 1 月 1 日
let date2 = new Date(2019, 1, 1); // 2019 年 2 月 1 日
console.log(date1 < date2); // true 
console.log(date1 > date2); // false 

JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第1张图片

5.1.5 日期格式化方法

Date 类型有几个专门用于格式化日期的方法,它们都会返回字符串:

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

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

5.1.6 日期/时间个格式化方法

Date 类型剩下的方法(见下表)直接涉及取得或设置日期值的特定部分。注意表中**“UTC 日期”,指的是没有时区偏移(将日期转换为 GMT)时的日期。**
JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第2张图片
JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第3张图片

let now = new Date(); 
let year = now.getFullYear(); 
let month = now.getMonth() + 1; // 得到的月份小1
let dates = now.getDate();
let arr = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'];
let day = now.getDay(); // 周日返回的是0,周一返回的是1

console.log('今天是:' + year + '年' + month + '月' + dates + '日' + arr[day]);
console.log('今天是:' + year + '-' + month + '-' + dates + '-' + arr[day]);

今天是:2021年10月24日星期日
今天是:2021-10-24-星期日

封装一个函数,返回当前的时分秒,格式是09:09:09,填充字符为0

// 封装一个函数,返回当前的时分秒,格式是09:09:09,填充字符为0
function getTime() {
    let time = new Date();
    let hour = time.getHours();
    hour = hour > 10 ? hour : '0'+hour;

    let min = time.getMinutes();
    min = min > 10 ? min : '0' + min;

    let sec = time.getSeconds();
    sec = sec > 10 ? sec : '0' + sec;

    return hour + ':' + min + ':' + sec;
}

console.log(getTime())

注意是 Date !!! 不是Data

5.1.7 获得日期的总的毫秒数-时间戳

不是当前时间的毫秒数,而是距离1970年1月1日过来多少毫秒数

// 获得Date总的毫秒数---时间戳
// 不是当前时间的毫秒数,而是距离1970年1月1日过来多少毫秒数
        var date = new Date();
        alert(date.valueOf()); //方法一 valueOf()
        alert(date.getTime()); //方法二 getTime()

        // 简单写法-最常用
        var date1 = +new Date();
        alert(date1);

        // H5新增
        alert(Date.now());

5.1.8 倒计时案例

核心算法:输入的时间减去现在的时间就是剩余的时间,即倒计时,但是不能拿着时分秒去相减,这样会有错误的结果,比如05-25

要用时间戳来做,用户输入的时间总毫秒数减去现在的总时间毫秒数,得到的就是剩余的毫秒数,然后转换为时分秒【时间戳转换为时分秒】

  • d = parseInt(总秒数/60/60/24);
  • h = parseInt(总秒数/60/60%24);
  • m = parseInt(总秒数/60%60);
  • s = parseInt(总秒数%60);
        // 倒计时效果
        function countDown(time) {
            var nowTime = +new Date(); //返回当前时间总的毫秒数
            var inputTime = +new Date(time); //返回的是用户输入时间总的毫秒数
            var times = (inputTime - nowTime) / 1000; //两者差,毫秒数

            var d = parseInt(times/24 /60 /60);
            d = d > 10 ? d : '0' + d;
            var h = parseInt(times/60 /60 %24);
            h = h > 10 ? h : '0' + h;
            var m = parseInt(times/60 %60);
            m = m > 10 ? m : '0' + m;
            var s = parseInt(times%60);
            s = s > 10 ? s : '0' + s;

            return d + '天' + h + '时' + m + '分' + s + '秒';
        }

        alert(countDown('2021-3-12 18:00:00'));

5.2 RegExp

ECMAScript 通过 RegExp 类型支持正则表达式。

5.2.1 创建–字面量形式

语法: 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;

所有元字符在模式中也必须转义,包括:( [ { \ ^ $ | ) ] } ? * + .
使用反斜杠来转义

// 匹配第一个"[bc]at",忽略大小写
let pattern2 = /\[bc\]at/i; 

// 匹配所有".at",忽略大小写
let pattern4 = /\.at/gi;

5.2.2 创建–构造函数形式

语法:接收两个参数,且都是字符串

  • 模式字符串,某些情况下需要转义
  • (可选的)标记字符串
// 匹配第一个"bat"或"cat",忽略大小写
let pattern1 = /[bc]at/i; 

// 跟 pattern1 一样,只不过是用构造函数创建的
let pattern2 = new RegExp("[bc]at", "i"); 

所有元字符都必须二次转义,包括转义字符序列,如\n(\转义后的字符串是\,在正则表达式字符串中则要写成\\)。
JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第4张图片
使用 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"

小例子

var reg=/\d+/g;
console.log(reg.test("789456"));//true

var reg2=new RegExp("\\d+","g");
console.log(reg2.test("1234444456"));//true
console.log(reg2.test("asdsa"));//false

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

let pattern2 = new RegExp("\\[bc\\]at", "i"); 

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

注意,虽然第一个模式是通过字面量创建的,第二个模式是通过 RegExp 构造函数创建的,但两个模式的 source 和 flags 属性是相同的。source 和 flags 属性返回的是规范化之后可以在字面量中使用的形式

5.2.4 RegExp 构造函数属性

适用于作用域中的所有正则表达式,会根据最后执行的正则表达式操作而变化。
可以通过 【全名】 和 【简写】两种不同的方式来访问。
JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第5张图片
通过这些属性可以提取出与 exec()和 test()执行的操作相关的信息。

全名形式举例:

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 
} 

以上代码创建了一个模式,用于搜索任何后跟"hort"的字符,并把第一个字符放在了捕获组中。不同属性包含的内容如下。

  • input 属性中包含原始的字符串。
  • leftConext 属性包含原始字符串中"short"之前的内容,rightContext 属性包含"short"之后的内容。
  • lastMatch 属性包含匹配整个正则表达式的上一个字符串,即"short"。
  • lastParen 属性包含捕获组的上一次匹配,即"s"。

简写形式举例:要使用中括号语法来访问,因为大多数简写形式都不是合法的 ECMAScript 标识符

let text = "this has been a short summer"; 
let pattern = /(.)hort/g; 
/* 
 * 注意:Opera 不支持简写属性名
 * IE 不支持多行匹配
 */ 
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 还有其他几个构造函数属性,可以存储最多 9 个捕获组的匹配项。

  • 通过 RegExp. $1 ~ RegExp.$9 来访问,分别包含第 1~9 个捕获组的匹配项
let text = "this has been a short summer"; 
let pattern = /(..)or(.)/g; 
if (pattern.test(text)) { 
 console.log(RegExp.$1); // sh 
 console.log(RegExp.$2); // t 
}

在这个例子中,模式包含两个捕获组。调用 test()搜索字符串之后,因为找到了匹配项所以返回true,而且可以打印出通过 RegExp 构造函数的$1 和$2 属性取得的两个捕获组匹配的内容。

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

5.2.5 RegExp 实例方法

exec

exec 该方法是专门为捕获组而设计的

功能:正则捕获的数据,一个数组;
参数:接收一个参数,即要应用模式匹配的字符串
特性:
    使用全局标记g;持续查找所有匹配项并返回
    不使用全局标记g;始终返回第一个匹配项信息
执行的过程
    检测字符串参数,获取正则表达式匹配文本
    找到匹配文本则返回一个数组
        第0个元素:与整个模式匹配的字符串
        其他元素:与捕获组匹配的字符串
    否则返回null
派生属性
    index 匹配项在字符串中的位置
    input 应用正则表达式的字符串
    length 返回数组元素的个数

添加链接描述

let text = "mom and dad and baby"; 
let pattern = /mom( and dad( and baby)?)?/gi; 

console.log(pattern.exec(text));   // ["mom and dad and baby"," and dad and baby"," and baby"]

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()后找到了一个匹配项。因为整个字符串匹配模式,所以 matchs数组的 index 属性就是 0。
数组的第一个元素是匹配的整个字符串,第二个元素是匹配第一个捕获组的字符串,第三个元素是匹配第二个捕获组的字符串。

test

test 方法主要是用来检测字符串是否符合正则表达式要求的规范,返回true或false

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

经常用于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()都返回正则表达式的字面量表示

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

这里的模式是通过 RegExp 构造函数创建的,但 toLocaleString()和 toString()返回的都是其字面量的形式。
正则表达式的 valueOf()方法返回正则表达式本身。

5.2.6 模式局限

JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第6张图片

JS详解对象篇-RegExp

5.2.7 正则表达式中的特殊字符

正则表达式中的特殊字符

正则表达式里面不需要加引号,不管是数字型还是字符串型

1 边界符
JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第7张图片
2 字符类
[ ] 字符类表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可选择的字符在方括号里面。
[-] 方括号内部范围符 -
字符组合:不需要空格,直接拼接到后面

let reg = /abc/;  //只要包含abc就可以
let rg = /[abc]/; // 只要包含有a 或者b 或者c 都返回true
let r = /^[abc]$/;  // 三选一,只有是a 或者b 或者c  这三个字母都是true

console.log(reg.test('abc and dad and baby'));   // true
console.log(rg.test('mom and dad and baby'));   // true
console.log(r.test('a'));   // true

let r = /^[a-z]$/;  // 26个英文字母任意一个都是true
let r = /^[a-zA-Z]$/;  // 26个英文字母(大小写都可以)任意一个都是true

[^] 如果在中括号里面有 ^ 表示取反的意思,不要和 边界符 ^ 混淆

let r = /^[^a-zA-Z]$/;  // 取反,不能包含这些元素

3 量词符
用来设定某个模式出现的次数
JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第8张图片

// * 相当于 >=0 可以出现0次或很多次
let reg = /^a*$/;

// + 相当于 >=1 可以出现1次或很多次
let reg = /^a+$/;  // 出现0次就是false

// ? 相当于 1 || 0 只允许出现1次或0次
let reg = /^a?$/;

如果要确定a的具体的次数的话,可以使用下面的三个量词:

// {3} 就是重复3次
let reg = /^a{3}$/;

// {3,} 就是重复大于等于3次
let reg = /^a{3,}$/;

// {3,6} 就是重复大于等于3并且小于等于6次
let reg = /^a{3,6}$/;

注意:量词中间不要有空格!!!

4 量词重复某个模式的次数

let r = /^[a-zA-Z0-9_-]{6,16}$/;  // 表示方括号里面的内容限定出现6-16次

5 案例:用户名验证分析

6 括号总结

  • 大括号 量词符:里面表示重复次数
  • 中括号 字符集合:匹配方括号内任意一个字符
  • 小括号:表示优先级
let r = /^abc{3}$/;    // 这里只是让c重复3次,abccc

let r = /^(abc){3}$/;    // 这里是让abc重复3次,abcabcabc

在线工具
正则表达式在线测试

7 预定义类
指的是某些常见模式的简写方式
JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第9张图片

5.3 原始值包装类型

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

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

s1 是一个包含字符串的变量,它是一个原始值。第二行紧接着在 s1 上调用了 substring()方法,并把结果保存在 s2 中。我们知道,原始值本身不是对象,因此逻辑上不应该有方法

当第二行访问 s1 时,是以读模式访问的,也就是要从内存中读取变量保存的值,这时后台会执行以下3个步骤:

  • 创建一个 String 类型的实例;
  • 调用实例上的特定方法;
  • 销毁实例。

所以上面的例子实际上执行了如下的内容:

let s1 = new String("some text");  // 创建一个 String 类型的实例
let s2 = s1.substring(2);          // 调用实例上的方法
s1 = null;                         // 销毁实例

这样就可以让原始值拥有对象的行为,这两者的区别是:

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

// 引用类型
const strObj = new String("text");
strObj.prop = "test";
// "test"
strObj.prop;

// 原始类型
const strPrim = "Primitive";
strPrim.prop = "test";
// undefined;
strPrim.prop;

strObj 是一个字符串的引用类型,也就是一个对象,而对象本身是可以拥有属性的。所以当 strObj.prop 被赋值之后,prop 这个属性就会被保存在 strObj 中,一直到 strObj 被销毁。

但是对于原始类型 strPrim 来说就不一样了,一旦过了 ln9,strPrim 的原始值包装类型就会被销毁,因此在 ln10 调用 strPrim.prop 时会返回 undefined。

可以显式地使用 Boolean、Number 和 String 构造函数创建原始值包装对象。
在原始值包装类型的实例上调用 typeof 会返回"object",所有原始值包装对象都会转换为布尔值 true。
Object 构造函数作为一个工厂方法,能够根据传入值的类型返回相应原始值包装类型的实例。

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

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

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

在这个例子中,变量 number 中保存的是一个值为 25 的原始数值,而变量 obj 中保存的是一个Number 的实例。

5.3.1 Boolean

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

let booleanObject = new Boolean(true);

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

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

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

在这段代码中,创建一个值为 false 的 Boolean 对象。然后,在一个布尔表达式中通过&&操作将这个对象与一个原始值 true 组合起来。这个表达式是对 falseObject对象而不是对它表示的值(false)求值,所有对象在布尔表达式中都会自动转换为 true,因此 falseObject 在这个表达式里实际上表示一个 true 值。那么true && true 当然是 true。

  • typeof 操作符对原始值返回"boolean",但对引用值返回"object"
  • Boolean 对象是 Boolean 类型的实例,在使用instaceof 操作符时返回 true,但对原始值则返回 false

强烈建议永远不要使用引用值(Boolean 对象)

5.3.2 Number

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

let numberObject = new Number(10); 

继承的方法:

  • valueOf()方法返回 Number 对象表示的原始数值,toLocaleString()
    toString()方法返回数值字符串。
  • toString()方法可选地接收一个表示基数的参数,并返回相应基数形式的数值字符串。
let num = 10; 
console.log(num.toString()); // "10" 
console.log(num.toString(2)); // "1010"

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

  • toFixed()方法返回包含指定小数点位数的数值字符串,不过的用0填充,多余的则四舍五入
  • toExponential(),接收一个参数,表示结果中小数的位数,但返回的是以科学记数法(也称为指数记数法)表示的数值字符串
  • toPrecision()方法会根据情况返回最合理的输出结果,可能是固定长度,也可能是科学记数法形式。接收一个参数,表示结果中数字的总位数(不包含指数)。本质上,toPrecision()方法会根据数值和精度来决定调用 toFixed()还是 toExponential()
let num = 10; 
console.log(num.toFixed(2)); // "10.00" 

let num = 10.005; 
console.log(num.toFixed(2)); // "10.01"

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

let num = 99; 
console.log(num.toPrecision(1)); // "1e+2" 
console.log(num.toPrecision(2)); // "99" 
console.log(num.toPrecision(3)); // "99.0" 

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

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 

Number.isInteger()方法,用于辨别一个数值是否保存为整数
IEEE 754 数值格式有一个特殊的数值范围,在这个范围内二进制值可以表示一个整数值。这个数值
范围从 Number.MIN_SAFE_INTEGER(2^53 + 1)到 Number.MAX_SAFE_INTEGER( 2^53 -1)。鉴别整数是否在这个范围内,可以使用 Number.isSafeInteger()方法。

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

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

5.3.3 String

String 是对应字符串的引用类型。
要创建一个 String 对象,使用 String 构造函数并传入一个数值

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

继承的方法:valueOf()toLocaleString()toString()都返回对象的原始字符串值。
每个 String 对象都有一个 length 属性,表示字符串中字符的数量。

let stringValue = "hello world"; 
console.log(stringValue.length); // "11" 
1 JavaScript字符

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

  • charAt()方法查找指定索引位置的 16 位码元,并返回该码元对应的字符
  • charCodeAt()方法可以查看指定码元的字符编码----> codePointAt() 接收 16 位码元的索引并返回该索引位置上的码点(code point)。码点是 Unicode 中一个字符的完整标识。
  • fromCharCode()方法用于根据给定的 UTF-16 码元创建字符串中的字符,可以接受任意多个数值,并返回将所有数值对应的字符拼接起来的字符串----> fromCodePoint()

对于 U+0000~U+FFFF 范围内的字符length、charAt()、charCodeAt()和 fromCharCode()返回的结果都跟预期是一样的。这是因为在这个范围内,每个字符都是用 16 位表示的,而这几个方法也都基于 16 位码元完成操作。只要字符编码大小与码元大小一一对应,这些方法就能如期工作。

这个对应关系在扩展到 Unicode 增补字符平面时就不成立了。问题很简单,即 16 位只能唯一表示65 536 个字符。这对于大多数语言字符集是足够了,在 Unicode 中称为基本多语言平面(BMP)。为了表示更多的字符,Unicode 采用了一个策略,即每个字符使用另外 16 位去选择一个增补平面。这种每个字符使用两个 16 位码元的策略称为代理对

为正确解析既包含单码元字符又包含代理对字符的字符串,可以使用 codePointAt()来代替charCodeAt()fromCodePoint()来代替fromCharCode()

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

// Unicode "Latin small letter C"的编码是 U+0063 
console.log(message.charCodeAt(2)); // 99 
// 十进制 99 等于十六进制 63 
console.log(99 === 0x63); // true

// Unicode "Latin small letter A"的编码是 U+0061 
// Unicode "Latin small letter B"的编码是 U+0062 
// Unicode "Latin small letter C"的编码是 U+0063 
// Unicode "Latin small letter D"的编码是 U+0064 
// Unicode "Latin small letter E"的编码是 U+0065 
console.log(String.fromCharCode(0x61, 0x62, 0x63, 0x64, 0x65)); // "abcde" 
// 0x0061 === 97 
// 0x0062 === 98 
// 0x0063 === 99 
// 0x0064 === 100 
// 0x0065 === 101 
console.log(String.fromCharCode(97, 98, 99, 100, 101)); // "abcde"
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(String.fromCharCode(97, 98, 55357, 56842, 100, 101)); // ab☺de 
console.log(String.fromCodePoint(97, 98, 128522, 100, 101)); // ab☺de 
2 normalize方法

某些 Unicode 字符可以有多种编码方式。有的字符既可以通过一个 BMP 字符表示,也可以通过一个代理对表示。比较操作符不在乎字符看起来是什么样的,因此这 3 个字符互不相等。为了解决这个问题,Unicode提供了 4种规范化形式,可以将类似上面的字符规范化为一致的格式。

使用 normalize()方法对字符串应用上述规范化形式,使用时需要传入表示哪种形式的字符串:“NFD”、“NFC”、“NFKD"或"NFKC”。

  • NFD(Normalization Form D)
  • NFC(Normalization Form C)
  • NFKD(Normalization Form KD)
  • NFKC(Normalization Form KC)

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

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("NFKC")); // true 
console.log(a1.normalize("NFC") === a3.normalize("NFC")); // true **
3 字符串操作方法

concat(),用于将一个或多个字符串拼接成一个新字符串,并不改变原来字符串的值 ,可以接收任意多个参数,一次性拼接多个字符串。

但更常用的方式是使用加号操作符(+),更加方便。

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

从字符串中提取子字符串:

  • slice()

    • 接收参数:第一个表示子字符串开始的位置,第二个参数是提取结束的位置(即该位置之前的字符会被提取出来)
    • 返回调用它们的字符串的一个子字符串
  • substr()

    • 接收参数:第一个表示子字符串开始的位置,第二个参数表示返回的子字符串数量
    • 返回调用它们的字符串的一个子字符串
  • substring()

    • 接收参数:第一个表示子字符串开始的位置,第二个参数是提取结束的位置(即该位置之前的字符会被提取出来)
    • 返回调用它们的字符串的一个子字符串

任何情况下,省略第二个参数都意味着提取到字符串末尾
不会修改调用它们的字符串,而只会返回提取到的原始新字符串值

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" ,不包括7
console.log(stringValue.substr(3, 7)); // "lo worl" ,第二个参数表示的是返回的字符数

参数是负值时:

  • slice()方法将所有负值参数都当成字符串长度加上负参数值
  • substr()方法将第一个负参数值当成字符串长度加上该值,将第二个负参数值转换为 0
  • substring()方法会将所有负参数值都转换为 0
let stringValue = "hello world"; 
// -3 会被转换为 8(长度加上负参数),实际上调用的是 slice(8)和 substr(8)
console.log(stringValue.slice(-3)); // "rld" 
console.log(stringValue.substring(-3)); // "hello world" 
console.log(stringValue.substr(-3)); // "rld", -3 会转换为 0

console.log(stringValue.slice(3, -4)); // "lo w" ,将第二个参数转换为 7,实际上相当于调用 slice(3, 7)
console.log(stringValue.substring(3, -4)); // "hel",将第二个参数转换为 0,相当于调用substring(3, 0),等价于 substring(0, 3),这是因为这个方法会将较小的参数作为起点,将较大的参数作为终点
console.log(stringValue.substr(3, -4)); // "" (empty string),第二个参数会被转换为 0,意味着返回的字符串包含零个字符,因而会返回一个空字符串
4 字符串位置方法

用于在字符串中定位子字符串

  • indexOf()
    • 从字符串开头开始查找字符串
    • 从字符串中搜索传入的字符串,并返回位置(如果没找到,则返回-1)
    • 可以接收第二个可选的参数,表示开始搜索的位置,从这个参数指定的位置开始向字符串末尾搜索,忽略该位置之前的字符
  • lastIndexOf()
    • 从字符串末尾开始查找字符串
    • 从字符串中搜索传入的字符串,并返回位置(如果没找到,则返回-1)
    • 可以接收第二个可选的参数,表示开始搜索的位置,会从这个参数指定的位置开始向字符串开头搜索,忽略该位置之后直到字符串末尾的字符
let stringValue = "hello world"; 
console.log(stringValue.indexOf("o")); // 4 
console.log(stringValue.lastIndexOf("o")); // 7 

console.log(stringValue.indexOf("o", 6)); // 7 
console.log(stringValue.lastIndexOf("o", 6)); // 4 

使用第二个参数并循环调用就可以在字符串中找到所有的目标子字符串

let stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit"; 
let positions = new Array(); 
let pos = stringValue.indexOf("e"); 
while(pos > -1) { 
 positions.push(pos); 
 pos = stringValue.indexOf("e", pos + 1); 
} 
console.log(positions); // [3,24,32,35,52] 
5 字符串包含方法

用于判断字符串中是否包含另一个字符串的方法

  • 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
let message = "foobarbaz"; 
console.log(message.startsWith("foo")); // true 
console.log(message.startsWith("foo", 1)); // false 

console.log(message.includes("bar")); // true 
console.log(message.includes("bar", 4)); // false

console.log(message.endsWith("bar")); // false 
console.log(message.endsWith("bar", 6)); // true 
6 trim方法

trim()方法会创建字符串的一个副本,删除前、后所有空格符,再返回结果,不改变原始字符串
trimLeft()trimRight()方法分别用于从字符串开始和末尾清理空格符

let stringValue = " hello world "; 
let trimmedStringValue = stringValue.trim(); 
console.log(stringValue); // " hello world " 
console.log(trimmedStringValue); // "hello world" 
7 repeat方法

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

8 padStart()和 padEnd()方法

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

console.log(stringValue.padStart(8, "bar")); // "barbafoo" 
console.log(stringValue.padStart(2)); // "foo" 

console.log(stringValue.padEnd(8, "bar")); // "foobarba" 
console.log(stringValue.padEnd(2)); // "foo" 
9 字符串迭代与解构

字符串的原型上暴露了一个@@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 c of "abcde") { 
 console.log(c); 
} 
// a 
// b 
// c 
// d 
// e

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

let message = "abcde"; 
console.log([...message]); // ["a", "b", "c", "d", "e"]
10 字符串大小写转换
  • 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" 

通常,如果不知道代码涉及什么语言,则最好使用地区特定的转换方法。

11 字符串模式匹配方法
  • match()方法
    • 本质上跟 RegExp 对象的 exec()方法相同
    • 接收一个参数,正则表达式字符串 或者 RegExp 对象
    • 返回的数组与RegExp 对象的 exec()方法返回的数组是一样的:第一个元素是与整个模式匹配的字符串,其余元素则是与表达式中的捕获组匹配的字符串(如果有的话)
  • search()方法
    • 参数是正则表达式字符串 或者 RegExp 对象
    • 返回模式第一个匹配的位置索引,如果没找到则返回-1
    • 始终从字符串开头向后匹配模式
let text = "cat, bat, sat, fat"; 
let pattern = /.at/; 
// 等价于 pattern.exec(text) 
let matches = text.match(pattern); 
console.log(matches.index); // 0 
console.log(matches[0]); // "cat" 
console.log(pattern.lastIndex); // 0 
let text = "cat, bat, sat, fat"; 
let pos = text.search(/at/); 
console.log(pos); // 1 ,即"at"的第一个字符在字符串中的位置
  • replace()方法
    • 接收两个参数:第一个参数可以是 RegExp 对象或 字符串(这个字符串不会转换为正则表达式),第二个参数可以是字符串 或 函数
    • 如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,第一个参数必须为正则表达式并且带全局标记
    • 第二个参数是字符串的情况下,有几个特殊的字符序列,可以用来插入正则表达式操作的值
    • 第二个参数可以是一个函数
      • 只有一个匹配项时,这个函数会收到 3 个参数:与整个模式匹配的字符串、匹配项在字符串中的开始位置,以及整个字符串。
      • 有多个捕获组的情况下,每个匹配捕获组的字符串也会作为参数传给这个函数,但最后两个参数还是与整个模式匹配的开始位置和原始字符串。
        JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第10张图片
let text = "cat, bat, sat, fat"; 
let result = text.replace("at", "ond"); 
console.log(result); // "cond, bat, sat, fat" 
result = text.replace(/at/g, "ond"); 
console.log(result); // "cond, bond, sond, fond"

这里,每个以"at"结尾的词都会被替换成"word"后跟一对小括号,其中包含捕获组匹配的内容$1

let text = "cat, bat, sat, fat"; 
result = text.replace(/(.at)/g, "word ($1)"); 
console.log(result); // word (cat), word (bat), word (sat), word (fat)
function htmlEscape(text) { 
 return text.replace(/[<>"&]/g, function(match, pos, originalText) { 
 switch(match) { 
 case "<": 
 return "<"; 
 case ">": 
 return ">"; 
 case "&": 
 return "&"; 
 case "\"": 
 return """; 
 } 
 }); 
} 
console.log(htmlEscape("

Hello world!

"
)); // "<p class="greeting">Hello world!

"
  • split()方法
    • 根据传入的分隔符将字符串拆分成数组
    • 分隔符可以是字符串,也可以是RegExp 对象
    • 第二个参数,即数组大小,确保返回的数组不会超过指定大小

注意在最后一次调用 split()时,返回的数组前后包含两个空字符串。这是因为正则表达式指定的分隔符出现在了字符串开头(“red”)和末尾(“yellow”)。

let colorText = "red,blue,green,yellow"; 
let colors1 = colorText.split(","); // ["red", "blue", "green", "yellow"] 
let colors2 = colorText.split(",", 2); // ["red", "blue"] 
let colors3 = colorText.split(/[^,]+/); // ["", ",", ",", ",", ""]
12 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 

返回的具体值可能因具体实现而异,实现所在的地区(国家和语言)决定了这个方法如何比较字符串。

5.4 单例内置对象

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

  • Object
  • Array
  • String
  • Global
  • Math

5.4.1 Global

ECMA-262 规定 Global对象为一种兜底对象,它所针对的是不属于任何对象的属性和方法。
在全局作用域中定义的变量和函数都会变成 Global 对象的属性 。

1 URL编码方法

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

  • 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"; 

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

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

这里使用 encodeURI()编码后,除空格被替换为%20 之外,没有任何变化。而 encodeURIComponent()方法将所有非字母字符都替换成了相应的编码形式。这就是使用 encodeURI()编码整个URI,但只使用encodeURIComponent()编码那些会追加到已有 URI 后面的字符串的原因。

解码:

  • decodeURI():只对使用 encodeURI()编码过的字符解码
  • decodeURIComponent():基本上就是解码所有特殊值
let uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.js%23start"; 

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

// http:// www.wrox.com/illegal value.js#start 
console.log(decodeURIComponent(uri)); 

不要在生产环境中使用 escape()和 unescape(),它们只能正确编码 ASCII 字符

2 eval() 方法

eval()方法就是一个完整的 ECMAScript 解释器,它接收一个参数,即一个要执行的 ECMAScript(JavaScript)字符串。
当解释器发现 eval()调用时,会将参数解释为实际的 ECMAScript 语句,然后将其插入到该位置。通过 eval()执行的代码属于该调用所在上下文,被执行的代码与该上下文拥有相同的作用域链。这意味着定义在包含上下文中的变量可以在 eval()调用内部被引用。

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

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

eval("let msg = 'hello world';"); 
console.log(msg); // Reference Error: msg is not defined

通过 eval()定义的任何变量和函数都不会被提升,这是因为在解析代码的时候,它们是被包含在一个字符串中的。它们只是在 eval()执行的时候才会被创建。

在严格模式下,在 eval()内部创建的变量和函数无法被外部访问,赋值给 eval 也会导致错误。

3 Global 对象属性

JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第11张图片
JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第12张图片

4 window 对象

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

var color = "red"; 
function sayColor() { 
 console.log(window.color); 
} 
window.sayColor(); // "red" 

另一种获取 Global 对象的方式是使用如下的代码:

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

这段代码创建一个立即调用的函数表达式,返回了 this 的值。如前所述,当一个函数在没有明确(通过成为某个对象的方法,或者通过 call()/apply())指定 this 值的情况下执行时,this 值等于Global 对象。因此,调用一个简单返回 this 的函数是在任何执行上下文中获取 Global 对象的通用方式。

5.4.2 Math

1 Math对象属性

保存数学中的一些特殊值
JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第13张图片

2 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); 
3 舍入方法
  • Math.ceil() :始终向上舍入为最接近的整数
  • Math.floor() :始终向下舍入为最接近的整数
  • Math.round() :执行四舍五入
  • Math.fround():返回数值最接近的单精度(32 位)浮点值表示
console.log(Math.ceil(25.9)); // 26 
console.log(Math.ceil(25.5)); // 26 
console.log(Math.ceil(25.1)); // 26 

console.log(Math.round(25.9)); // 26 
console.log(Math.round(25.5)); // 26 
console.log(Math.round(25.1)); // 25 

console.log(Math.fround(0.4)); // 0.4000000059604645 
console.log(Math.fround(0.5)); // 0.5 
console.log(Math.fround(25.9)); // 25.899999618530273 

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,[0, 1)

使用 Math.random()从一组整数中随机选择一个数

number = Math.floor(Math.random() * total_number_of_choices + first_possible_value)

从 1~10 范围内随机选择一个数

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

selectFrom()接收两个参数:应该返回的最小值和最大值。通过将这两个值相减再加 1 得到可选总数,然后再套用上面的公式。

function selectFrom(lowerValue, upperValue) { 
 let choices = upperValue - lowerValue + 1; 
 return Math.floor(Math.random() * choices + lowerValue); 
} 

let num = selectFrom(2,10); 
console.log(num); // 2~10 范围内的值,其中包含 2 和 10

从一个数组中随机选择一个元素就很容易

let colors = ["red", "green", "blue", "yellow", "black", "purple", "brown"]; 
let color = colors[selectFrom(0, colors.length-1)]; 

如果是为了加密而需要生成随机数(传给生成器的输入需要较高的不确定性),那么建议使用 window.crypto.getRandomValues()

5 其他方法

JavaScript高级程序设计(第4版)-第五章 基本引用类型学习笔记_第14张图片

5.5 小结

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

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

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

由于原始值包装类型的存在,JavaScript 中的原始值可以被当成对象来使用。有 3 种原始值包装类型:Boolean、Number 和 String。它们都具备如下特点。

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

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

你可能感兴趣的:(前端学习,javascript)