文章目录
- 基本引用类型
- 1.Date
- 1.1 继承的方法
- 1.2 日期格式化方法
- 1.3 日期/时间组件方法
- 2.RegExp正则表达式
- 2.1 RegExp 实例属性
- 2.2 RegExp 实例方法
- 2.3 RegExp 构造函数属性
- 3.原始值包装类型
- 3.1 Boolean
- 3.2 Number
- 3.3 String
- 3.3.1 JavaScript 字符
- 3.3.2 normalize()方法
- 3.3.3 字符串操作方法
- 3.3.4 字符串位置方法
- 3.3.5 字符串包含方法
- 3.3.6 trim()
- 3.3.7 repeat()
- 3.3.8 padStart()和 padEnd()
- 3.3.9 字符串迭代与解构
- 3.3.10 字符串大小写转换
- 3.3.11 字符串模式匹配方法
- 3.3.12 localeCompare()
- 3.3.13 HTML 方法
- 4.单例内置对象
- 4.1 Global对象
- URL 编码方法
- eval()方法
- Global 对象属性
- window 对象
- 4.2 Math
- Math 对象属性
- min()和 max()方法
- 舍入方法
- random()方法
- 其他方法
- 5.小结
基本引用类型
引用值(或对象)是某个特定引用类型的实例。
引用类型:
- 是把数据和功能组织到一起的结构,经常被人错误地称作“类”。
- 也被称为对象定义,因为它们描述了自己的对象应有的属性和方法。
对象:
- 对象被认为是某个特定引用类型的实例。
- 新对象通过使用 new 操作符后跟一个构造函数(constructor)来创建。
- 构造函数就是用来创建新对象的函数
let now = new Date();
1.Date
Date 类型将日期保存为自 1970 年 1 月 1 日午夜(零时)至今所经过的毫秒数。
创建日期对象:
let now = new Date();
- 无参:创建的对象将保存当前日期和时间
- 有参:传入其毫秒表示(1970 年 1 月 1 日午夜之后的毫秒数)
两个辅助方法
Date.parse()
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 的实例
- 包含两个额外的属性:
index
和input
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;
步骤:
- 创建实例
- 调用方法
- 销毁实例
引用类型与原始值包装类型的主要区别:对象的生命周期
- 通过 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 对象。原因:在处理原始数值和引用数值时,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
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"]
对比:fromCharCode
、fromCodePoint
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("NFKC"));
// true
console.log(a1.normalize("NFC") === a3.normalize("NFC"));
// true
3.3.3 字符串操作方法
concat()
:
- 将一个或多个字符串拼接成一个新字符串
- 可以接收任意多个参数
- 更常用的方式:使用加号操作符(+)
从字符串中提取子字符串的方法:
slice()
substr()
substring()
- 第一个参数表示子字符串开始的位置,第二个参数表示子字符串结束的位置
- 对
slice()
和substring()
:第二个参数:提取结束的位置 - 对
substr()
:第二个参数:返回的子字符串长度 - 任何情况下:
- 省略第二个参数都意味着提取到字符串末尾
- 不会修改调用它们的字符串,只会返回提取到的原始新字符串值
某个参数是负值时:
slice()
:所有负值参数:字符串长度加上负参数值substr()
:第一个负参数值:字符串长度加上该值,第二个负参数值:0substring()
:所有负参数值:0
3.3.4 字符串位置方法
用于在字符串中定位子字符串:
indexOf()
和lastIndexOf()
- 从字符串中搜索传入的字符串,返回位置(没找到返回-1)
- 区别:
indexOf()
:从字符串开头开始查找子字符串lastIndexOf()
:从字符串末尾开始查找子字符串- 第二个参数(可选):开始搜索的位置
3.3.5 字符串包含方法
判断字符串中是否包含另一个字符串:
startsWith()
、endsWith()
和includes()
startsWith()
:从索引0开始endsWith()
:从string.length - substring.length
开始includes()
:检查整个字符串
举例:由代码可以看出,就算包含,但不是从相应位置匹配的也是false
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()
- 可选
- 表示应该当作字符串末尾的位置
3.3.6 trim()
trim()
:
- 创建字符串的一个副本,删除前、后所有空格符
- 返回副本
- 原始字符串不受影响
trimLeft()
和trimRight()
:从字符串开始或末尾清理空格符
3.3.7 repeat()
repeat()
:
- 参数:整数
- 要将字符串复制多少次
- 返回:拼接所有副本后的结果
3.3.8 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"
3.3.9 字符串迭代与解构
@@iterator
方法:表示可以迭代字符串的每个字符。
let message = "abcde";
console.log([...message]);
// ["a", "b", "c", "d", "e"]
3.3.10 字符串大小写转换
toLowerCase()
和toUpperCase()
:
- 都变小写、都变大写
toLocaleLowerCase()
和 toLocaleUpperCase()
:
- 在特定地区实现
- 如土耳其语:Unicode 大小写转换需应用特殊规则,要使用地区特定的方法才能实现正确转换
3.3.11 字符串模式匹配方法
match()
方法:
- 跟 RegExp 对象的
exec()
方法相同 - 参数:正则表达式的字符串或RegExp对象
- 返回的数组与 exec()方法的一样:
- 第一个元素:与整个模式匹配的字符串
- 其他元素:与捕获组匹配的字符串(如果有)
let matches = text.match(pattern);等价于pattern.exec(text)
search()
方法:
- 参数:与
match()
相同 - 返回模式第一个匹配的位置索引,没找到返回-1
- 从字符串开头向后匹配
replace()
方法:
- 第一个参数:一个 RegExp 对象或一个字符串(不会转换为正则表达式)
- 第二个参数:一个字符串或函数
- 要想替换所有子字符串:第一个参数为正则表达式且带全局标记
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
- 每个:全局标记/g
- 以"at"结尾的词:(.at)
- 替换成"word"后跟一对小括号:“word ($1)”
- 捕获组匹配的内容:(.at)
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("<p class=\"greeting\">Hello world!</p>"));
// "<p class="greeting">Hello world!</p>"
split()
方法:
- 根据分隔符将字符串拆分成数组
- 分隔符参数:字符串、RegExp对象
- 第二个参数(可选):数组大小,确保返回的数组不会超过指定大小
let colorText = "red,blue,green,yellow";
let colors1 = colorText.split(","); // ["red", "blue", "green", "yellow"]
let colors2 = colorText.split(",", 2); // ["red", "blue"]
3.3.12 localeCompare()
- 比较两个字符串,按照字母表顺序,返回
- 字符串应该排在字符串参数前头,则返回负值(一般是-1)
- 后头,返回正值:一般是1
- 字符串与字符串参数相等:一般是0
- 省流:对象应该排在前面返回-1,后面1
let stringValue = "yellow";
console.log(stringValue.localeCompare("brick")); // 1
console.log(stringValue.localeCompare("yellow")); // 0
console.log(stringValue.localeCompare("zoo")); // -1
返回的具体值可能因具体实现而异,建议这样:用是否大于0来判断。
function determineOrder(value) {
let result = stringValue.localeCompare(value);
if (result < 0) {
console.log(`The string 'yellow' comes before the string '${value}'.`);
} else if (result > 0) {
console.log(`The string 'yellow' comes after the string '${value}'.`);
} else {
console.log(`The string 'yellow' is equal to the string '${value}'.`);
}
}
独特之处:根据所在的地区(国家和语言)决定了这个方法如何比较字符串。(所以带有local)
3.3.13 HTML 方法
这些方法基本不用了:结果通常不是语义化的标记。
4.单例内置对象
内置对象:“任何由 ECMAScript 实现提供、与宿主环境无关,并在 ECMAScript程序开始执行时就存在的对象”。
如:Object、Array、String、Global、Math。
4.1 Global对象
- 一种兜底对象,所针对的是不属于任何对象的属性和方法
- 在全局作用域中定义的变量和函数都会变成 Global 对象的属性
Global对象上的一些方法:
- URL 编码方法
- eval()方法
URL 编码方法
encodeURI()
和 encodeURIComponent()
方法:
- 用于编码统一资源标识符(URI),以便传给浏览器
- 有效的 URI 不能包含某些字符,使用 URI 编码方法可以让浏览器理解URL,并用特殊的 UTF-8 编码替换掉无效字符
ecnodeURI()
方法用于对整个 URI 进行编码encodeURIComponent()
方法用于编码 URI 中单独的组件- 区别:
encodeURI()
不会编码属于 URL 组件的特殊字符,比如冒号、斜杠、问号、井号 - 而
encodeURIComponent()
会编码它发现的所有非标准字符 - 一般使用
encodeURI()
编码整个URI - 只使用
encodeURIComponent()
编码会追加到已有 URI 后的字符串
例子:
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()
和encodeURIComponent()
相对的是decodeURI()
和decodeURIComponent()
decodeURI()
只对使用encodeURI()
编码过的字符解码decodeURIComponent()
解码所有被encodeURIComponent()
编码的字符
eval()方法
这个方法就是一个完整的 ECMAScript 解释器,它接收一个参数,即一个要执行的 ECMAScript(JavaScript)字符串。
例子:两条语句等价。
eval("console.log('hi')");
console.log("hi");
作用原理:
- eval()调用:解释器会将其当作JS语句,插入到该位置
- 通过 eval()执行的代码属于该调用所在上下文,被执行的代码与该上下文拥有相同的作用域链
- 通过 eval()定义的变量和函数不会被提升:在解析代码时,它们是被包含在一个字符串中的。只有在 eval()执行的时候才会被创建。
上下文相关例子:
- 定义在包含上下文中的变量可以在 eval()调用内部被引用
let msg = "hello world";
eval("console.log(msg)"); // "hello world"
//其实就是
console.log(msg)
- 同理:在 eval()内部定义函数或变量,可以在外部代码中引用
eval("function sayHi() { console.log('hi'); }");
sayHi();
在严格模式下:
- 在 eval()内部创建的变量和函数无法被外部访问
- 赋值给 eval 会导致错误
Global 对象属性
分为:特殊值和构造函数。
window 对象
- 浏览器将 window 对象实现为 Global对象的代理
- 所有全局作用域中声明的变量和函数都变成了 window 的属性
- 详情见第12章
4.2 Math
注意:Math 对象上提供的计算要比直接在 JavaScript 实现快得多: Math 对象上的计算使用了 JavaScript 引擎中更高效的实现和处理器指令。但, Math 计算的精度会因浏览器、操作系统、指令集和硬件而异。
Math 对象属性
是一些数学中的特殊值,了解一下:
min()和 max()方法
- 接收任意多个参数
- 返回最小/最大值
舍入方法
Math.ceil()
:向上舍入为最接近的整数Math.floor()
:向下舍入为最接近的整数Math.round()
:四舍五入Math.fround()
:返回数值最接近的单精度(32 位)浮点值表示
random()方法
Math.random()
:
- 返回一个[0,1)内的随机数
- 想从 1~10 范围内随机选择一个数:
let num = Math.floor(Math.random() * 10 + 1);
为什么要用Math.floor
:若随机数取0.9999999,则会算出9.999999+1=10.999999,向下取整得到10.
可以提炼出公式,从一组整数中随机选择一个数:
total_number_of_choices
:可选数字个数first_possible_value
:第一个数
number = Math.floor(Math.random() * total_number_of_choices + first_possible_value)
例子:
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()
其他方法
大概看看,要用到再说: