在 ECMAScript 中,引用类型是把数据和功能组合到一起的结构(不能称之为“类”,与类不是一个概念)。引用类型描述了自己的对象应有的属性和方法,故也被称为对象定义。引用值(或者对象)是某个特定引用类型的实例。
新对象通过使用 new 操作符后跟一个构造函数来创建。构造函数就是用来创建新对象的函数,表示了对象的类型。
1. Object
Object 类型在 ECMAScript 中十分常用。虽然 Object 的实例没有多少功能,但很适合存储和在应用程序间交换数据。
<>
创建 Object 类型的实例有两种方法:
- 使用 new 操作符和 Object 构造函数。如:(例1)
ver person = new Object();
person.name = "ZhouHang";
person.age: 29;
- 使用对象字面量表示法。**对象字面量是对象定义的简写形式,目的是为了简化包含大量属性的对象的创建。**如:(例2)
var person = {
name:"ZhouHang",
age:29
}; //此段代码定义了与上例相同的person对象。
- person 后面的赋值操作符表示后面要期待一个值。此时形成了一个表达式上下文。(表达式上下文指的是期待返回值的上下文)
- 左大括号({)出现在表达式上下文中,表示对象字面量开始,即表示一个表达式的开始。(若是 { 出现在语句上下文中,比如 if 语句的条件后面,则表示一个语句块的开始。)
- 逗号用于在对象字面量中分隔属性,但同一个对象字面量中最后一个属性后不写逗号。
- 在对象字面量表示法中,属性名可以是字符串或数值。数值属性会自动转换为字符串。如:(例3)
var person = {
name:"ZhouHang",
age:29,
5:true
};
- 也可以用字面量表示法来定义只有一个默认属性和方法的对象,只需在大括号中写一个空格即可:(例4)
var person = {};
person.name = "ZhouHang";
person.age = 29;
//与例1等效
注意:
- 在使用对象字面量定义对象时,并不会实际调用 Object 构造函数。
- 虽然两种方法都可行,但使用对象字面量表示法代码更少且更加美观。
属性的存取也有两种方法:
- 点语法:(例5)
var person = {
name:"ZhouHnag",
age:29
};
console.log(person.name);
2.中括号语法
使用中括号语法时,要在括号内使用属性名的字符串形式:(例6)
var person = {
name:"ZhouHnag",
age:29
};
console.log(person["name"]);
- 两种存取方式从功能上没有区别,但使用中括号语法可以通过变量访问属性。
- 如果属性名中包含可能会导致语法错误的字符或者包含关键字、保留字时,可以使用中括号语法。如:(例7)
person["first name"] = "ZhouHang";
// 因为"first name"中包含一个空格,所以不能使用点语法来访问。
(属性名中是可以包含非字母数字字符的,这时候只需要用中括号语法存取就行了)
- 点语法是首选的属性存取方式,除非访问属性时必须使用变量。
2. Array
Array 是 ECMAScript 中除 Object 外最常用的类型。
ECMAScript 数组跟其他编程语言的数组有很大区别。虽然也是有序数组,但数组中每个槽位可以存储任意类型的数据。并且 ECMAScript 数组是动态大小的,会随着数据添加而自动增长。
2.1 创建数组
1. 使用 Array 构造函数:
(例8)
var name = new Array();
- 如果知道数组元素的数量,则可以给构造函数传入一个值,然后 length 属性会被自动创建并设置为这个值:(例9)
var name = new Array(10); //创建一个初始 length 为10的数组
- 也可以给 Array 构造函数传入要保存的元素。
var name = new Array("ZhouHang","Nicholas","");
注意:创建数组时可以给构造函数传一个值。不过,如果这个值是数值,则会创建一个长度为指定数值的数组;而如果这个值是其它类型的,则会创建一个只包含该特定值的数组。如:(例10)
var name = new Array(8); //创建一个只包含8个元素的数组
var color = new Array("red"); //创建一个只包含一个元素,即字符串"red"的数组
- 使用 Array 构造函数时,也可以省略 new 操作符。
2.使用数组字面量表示法。
数组字面量是指在中括号中包含以逗号分隔的元素列表:(例11)
var colors = Array["red","blue","yellow","purple"]; //创建一个包含3个元素的数组
var names = Array[]; //创建一个空数组
var values = Array[1,2]; //创建一个包含2个元素的数组
var values2 = Array[1,3,]; //创建一个包含2个元素的数组(不推荐这样写)
注意:同对象一样,在使用数字字面量表示法创建数组时不会调用 Array 函数。
3. from ()方法:ES6新增的用于创建数组的静态方法,用于将类数组结构转换为数组实例。
4. of ()方法:ES6新增的第二个用于创建数组的静态方法,用于将一组参数转换为数组实例。
2.2 数组空位
使用数组字面量初始化数组时,可以使用一串逗号来创建空位。ECMAScript 会将逗号之间相应索引位置的值当成空位。ES6 新增方法会将这些空位当成存在的元素,只是值为 undefined;而 ES6以前的的方法则会忽略这个空位,但具体行为因方法而异。
在实践中应尽量避免使用数组空位。
2.3 数组索引
要取得或设置数组的值,需要使用中括号并提供相应值的数字索引。在中括号中提供的索引表示要访问的值。如果索引小于数组包含的元素数,则返回存储在相应位置的元素。如果把一个值设置给超过数组最大索引的索引,则数组长度会自动扩展到该索引值加1。如:(例12)
var names = ["ZhouHnag","ShiJiu","wang"]; //定义一个字符串数组
alert(names[0]); //显示第一项
names[2] = "Jie"; //修改第三项为"Jie"
names[3] = "wangsjijiu"; //添加第四项"wangshijiu"
- 上例中
alert(names[0];)
表示一个带有一条指定信息(names数组中的第一个元素)和一个 OK 按钮的警示框。alert() 期待字符串。如下图:(例13)
- 数组中元素的数量保存在 length 属性中,这个属性值始终返回0或大于0的值。数组 length属性不是只读的,通过修改 length 属性,可以从末尾删除或添加元素。若果将 length 设置为大于数组元素数的值,则没有被赋予相应值的元素会以 undefined 填充。(例14)
var names = ["ZhouHang","LiNing","cat"];
alert(names[3]); //undefined
alert(names[2]); //cat
names.length = 4; //length值大于数组元素数
alert(names[3]); //undefined
names[names.length] = "wo"; //添加一个元素
alert(names[3]); //undefined
alert(names[4]); //wo
注意:数组最多可以包含4 294 967 295个元素。若尝试添加更多项,则会导致抛出错误;若以这个最大值作为初始值创建数组,则会导致脚本运行时间过长的错误。
2.4 检测数组
判断一个对象是不是数组,是一个经典的 ECMAScript 问题。在只有一个网页(只有一个全局作用域)的情况下,使用 instanceof 操作符即可。而当网页设计多个不同的全局执行上下文时,就要使用 Array.isArray() 方法,这个方法不关注一个值在哪个全局执行上下文中创建。
语法: instanceof 操作符:
if(value instanceof Array){
//操作数组
}
Array.isArray() 方法:
if(Array.isArray(value)){
//操作数组
}
2.5 转换方法
对所有对象都有 toLocaleString()、toString() 和 valueOf () 方法:
valueOf() 返回的是数组本身、
toString() 返回由数组中每个值的等效字符串拼接而成的一个逗号分隔的字符串,即对数组的每个值都要调用 toString() 方法,以得到最终的字符串。
toLocaleString() 方法经常也会返回与 toString()和 valueOf()方法相同的值,但也不总是如此。当调用数组的
toLocaleString()方法时,它也会创建一个数组值的以逗号分隔的字符串。而与前两个方法唯一的不同之处在于,这一次为了取得每一项的值,调用的是每一项的
toLocaleString()方法,而不是 toString()方法。
- 数组继承的 toLocaleString()、toString()和 valueOf()方法,在默认情况下都会以逗号分隔的字符串的形式返回数组项。而如果使用 join()方法,则可以使用不同的分隔符来构建这个字符串。join()方法只接收一个参数,即用作分隔符的字符串,然后返回包含所有数组项的字符串。如:(例15)
var colors = ["red", "green", "blue"];
alert(colors.join(",")); //red,green,blue
alert(colors.join("||")); //red||green||blue
若不给 join() 传入任何参数,或者传入 undefined,则仍使用逗号作为分隔符。
注意:如果数组中的某一项的值是 null 或者 undefined,那么该值在 join()、toLocaleString()、toString()和 valueOf()方法返回的结果中以空字符串表示。
2.6 栈方法
数组对象可以像栈一样,栈是一种先进后出(LIFO)的结构,也就是最近添加的项先被删除。数据项的插入(称为推入)和删除(弹出) 只在栈的一个地方发生,即栈顶。
ECMAScript 数组提供了 push() 和 pop () 方法,以实现类似栈的行为。
- push() 方法接受任意数量的参数,并将它们添加到数组末尾,返回数组的最新长度。
- pop() 方法用于删除数组的最后一项,同时减少数组的 length 值,返回被删除的值。
栈方法可以与数组的其他任何方法一起使用。
2.7 队列方法
队列以先进先出(FIFO)的形式限制访问。在列表末尾添加数据,但从列表开头获取数据。使用 shiift() 和 push(),可以把数组当成队列来使用。shift() 方法会删除数组的第一项并返回它,然后数组长度减一。
ECMAScript 还提供了unshift() 方法,unshift() 即执行跟 shift() 相反的操作**在数组开头添加任意多个值,然后返回新数组的长度。**通过使用 unshift() 和 pop() ,可以在相反方向上模拟队列,即在数组开头添加新数据,在数组末尾取得数据。
2.8 排序方法
数组有两种方法可以对元素重新排序:reverse() 和 sort().
- reverse() 方法:将数组元素反向排序。
不够灵活,所以有了sort() 方法。 - sort() 方法:按照升序重新排列数组元素。
sort () 会在每一项上调用String() 转型函数,然后比较字符串来决定顺序。
即使数组的元素都是数值,它也会先把数组转换为字符串再比较、排序。这就产生一个问题,数值所对应的字符串大小关系并不一定与数值本身一致。因此,sort() 可以接受一个比较函数,用于判断哪个值应该排在最前面。
比较函数接受两个参数,如果第一个参数应该排在第二个参数的前面,就返回负值;如果两个参数相等,就返回0;如果第一个参数应该排在第二个参数的后面,就返回正值。
(例16)
function compare(value1,value2) {
if(value1 < value2) {
return -1;
} else if(value1 > value2){
return 1;
} else {
return o;
}
} //这个比较函数可以适用于大多数的数据类型,可以把它当做参数传给 sort() 方法。如下:
var values =[2,5,6,3,7];
values.sort(compare);
alert(values); //2,3,5,6,7
- 比较函数也可以产生降序效果,只需要把返回值交换一下即可:(例17)
function compare(value1,value2) {
if(value1 < value2) {
return 1;
} else if(value1 > value2){
return -1;
} else {
return o;
}
}
var values =[2,5,6,3,7];
values.sort(compare);
alert(values); //7,6,5,3,2
- 此比较函数还可以写为一个箭头函数:
var values = [2,5,6,3,7];
values.sort((a,b) => a < b ? 1 : a > b ? -1 : 0);
alert(values); // 7,6,5,3,2
如果只是想反转数组的顺序,reverse()更简单也更快。
注意:reverse()和sort()都返回调用它们的数组的引用。
如果数组的元素是数值,或者是其valueOf()方法返回数值的对象(如Date对象),这个比较函数还可以写得更简单,因为这时可以直接用第二个值减去第一个值,比较函数就是要返回小于0、0和大于0的数值,因此减法操作完全可以满足要求。
2.9 数组方法
数组中的操作元素的方法:
- concat()方法
可在现有数组全部元素基础上创建一个新数组(它首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组)。
如果传入一个或多个数组,则concat()会把这些数组的每一项都添加到结果数组。如果参数不是数组,则直接把它们添加到结果数组末尾。 - slice()方法
slice()方法用于 创建 一个包含原有数组中一个或多个元素的新数组,可接收一个或两个参数:返回元素的开始索引和结束索引。
如果只有一个参数,则slice()会返回该索引到数组末尾的所有元素。如果有两个参数,则slice()返回从开始索引到结束索引对应的所有元素(其中不包含结束索引对应的元素)。注意,该操作不影响原始数组。
注意: 如果slice()的参数有负值,那么就以数值长度加上这个负值的结果确定位置。比如,在包含5个元素的数组上调用slice(-2,-1),就相当于调用slice(3,4)。如果结束位置小于开始位置,则返回空数组。
- splice()方法
splice()方法的主要目的,是 在数组中间插入元素,但有 3 种不同的方式使用该方法:
- 删除
需要给splice()传 2 个参数:要删除的第一个元素的位置和要删除的元素数量。可以从数组中删除任意多个元素,比如splice(0, 2)会删除前两个元素; - 插入
需要给splice()传 3 个参数:开始位置、0(要删除的元素数量)和要插入的元素,可以在数组中指定的位置插入元素。第三个参数之后还可以传第四个、第五个参数,乃至 任意多个 要插入的元素。比如,splice(2, 0, “red”, “green”)会从数组位置 2 开始插入字符串"red"和"green"。 - 替换
splice()在删除元素的同时可以在指定位置插入新元素,同样要传入3个参数: 开始位置、要删除元素的数量和要插入的任意多个元素。要插入的元素数量不一定跟删除的元素数量一致。比如,splice(2, 1, “red”, “green”)会在位置 2 删除一个元素,然后从该位置开始向数组中插入"red"和"green"。
splice()方法始终返回这样一个数组,它包含从数组中被删除的元素(如果没有删除元素,则返回空数组)。
2.10 搜索和位置方法
搜索数组的方法有按严格相等搜索和按断言函数搜索。
2.10.1 严格相等
ECMAScript提供了 3 个严格相等的搜索方法:
- indexOf():从数组第一项开始往后搜索;
- lastIndexOf():从数组最后一项开始向前搜索;
- includes():从数组第一项开始往后搜索。
indexOf()和lastIndexOf()都返回要查找的元素在数组中的位置,如果没找到则返回-1。
includes()返回布尔值,表示是否至少找到一个与指定元素匹配的项。在比较第一个参数跟数组每一项时,会使用全等(===)比较,也就是说两项必须严格相等。
2.10.2 断言函数
ECMAScript 也允许按照定义的断言函数搜索数组,每个索引都会调用此函数。断言函数的返回值决定了相应索引的元素是否被认为匹配。
断言函数接收 3 个 参数:元素、索引 和 数组本身。其中元素是数组中当前搜索的元素,索引是当前元素的索引,数组是正在搜索的数组。断言函数返回真值,表示是否匹配。
find()方法: 返回 第一个匹配的 元素;
findIndex()方法:返回 第一个匹配元素的 索引。
【共同点】:
- 都使用了断言函数;
- 两个方法都从数组的最小索引开始;
- 也都接收第 2 个可选参数,用于指定断言函数内部this的值。
2.11 迭代方法
ECMAScript 为数组定义了 5 个 迭代方法。每个方法接收两个参数:以每一项为参数运行的函数,以及可选的作为函数运行上下文的作用域对象(影响函数中this的值)。传给每个方法的函数接收 3 个 参数:数组元素、元素索引 和 数组本身。
数组的 5 个迭代方法:
- every():对数组每一项都运行传入的函数,如果对每一项函数都返回true,则该方法返回true;
- filter():对数组每一项都运行传入的函数,函数返回true的项会组成数组之后返回;
- forEach():对数组每一项都运行传入的函数,没有返回值;
- map():对数组每一项都运行传入的函数,返回 由每次函数调用的结果构成的数;
- some():对数组每一项都运行传入的函数,如果有一项函数返回true,则该方法返回true。
注意: 这 5 个方法都不会改变调用它们的数组。
2.12 归并方法
ECMAScript 为 数组 提供了两个 归并方法:
- reduce():从数组第一项开始 遍历 到最后一项;
- reduceRight():从最后一项开始 遍历 至第一项。
- 两个方法都会迭代数组的所有项,并在此基础上构建一个最终返回值。且都接收两个参数:对每一项都会运行的归并函数,以及 可选的以之为归并起点的初始值 。
- 传给reduce()和reduceRight()的并归函数接收4个参数:上一个归并值、当前项、当前项的索引和数组本身。该函数返回的任何值都会作为下一次调用同一个函数的第一个参数。
- 如果没有给这两个方法传入可选的第二个参数(作为归并起点值),则第一次迭代将从数组的第二项开始,因此传给归并函数的第一个参数是数组的第一项,第二个参数是数组的第二项。
- 使用reduce()函数执行累加数组中所有数值的操作
- reduceRight()方法与reduce()类似,只是方向相反。
- 究竟是使用reduce() 还是reduceRight() 只取决于遍历数组元素的方向。
3. Date
对象被认为是某个特定引用类型的实例。新对象通过使用new操作符后跟一个构造函数来创建。构造函数就是用来创建新对象的函数。
ECMAScript还提供了:
Date.now()
方法,返回表示方法执行时日期和时间的毫秒数;
Date.parse()
方法接收一个表示日期的字符串参数,尝试将这个字符串转换为表示该日期的毫秒数。
如果直接把表示日期的字符串传给Date构造函数,那么Date会在后台调用Date.parse()
注意:Date.UTC()也会被Date构造函数隐式调用,但有一个区别:这种情况下创建的是本地日期,不是GMT日期。
4. RegExp
ECMAScript通过RegExp类型支持正则表达式。正则表达式使用类似Perl的简洁语法来创建:
let expression = /pattern/flags;
每个正则表达式可以带零个或多个flags(标记),用于控制正则表达式的行为。下面给出了表示匹配模式的标记。
g
:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束i
:不区分大小写,表示在查找匹配时忽略pattern和字符串的大小写。
m 多行模式,表示查找到一行文本末尾时会继续查找。y
:粘附模式,表示只查找从lastIndex开始及之后的字符串。u
:Unicode模式,启用Unicode匹配。s
:dotAll模式,表示元字符.匹配任何字符(包括\n或\r)。
RegExp实例的主要方法是exec()
,主要用于配合捕获组使用。这个方法只接收一个参数,即要应用模式的字符串。如果找到了匹配项,则返回包含第一个匹配信息的数组;如果没找到匹配项,则返回null;
正则表达式的另一个方法是test()
,接收一个字符串参数。如果输入的文本与模式匹配,则参数返回true,否则返回false。这个方法适用于只想测试模式是否匹配,而不需要实际匹配内容的情况。test()经常用在if语句中。
无论正则表达式是怎么创建的,继承的方法toLocaleString()
和toString()
都返回正则表达式的字面量表示。正则表达式的valueOf()
方法返回正则表达式本身。
5. 原始值包装类型
为了方便操作原始值,ECMAScript提供了 3 种特殊的引用类型:Boolean、Number 和 String。
每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型的对象,来暴露操作原始值的各种方法。
实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。后台过程如下:
(1) 创建 String/Boolean/Number 类型的一个实例;
(2) 在实例上调用指定的方法;
(3) 销毁这个实例
引用类型与基本包装类型的主要区别就是对象的生存期。使用 new 操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。这意味着我们不能在运行时为基本类型值添加属性和方法。
- Boolean
Boolean 类型的实例重写了valueOf()方法,返回基本类型值true 或false;重写了toString()方法,返回字符串"true"和"false"。可是,Boolean 对象在ECMAScript 中的用处不大,因为它经常会造成人们的误解。 - String
- 字符串方法:用于访问字符串中特定字符的方法:charAt() 和charCodeAt() 两个方法都接收一个参数,即基于0的字符位置,返回 该位置的字符。
- 字符串操作方法:
concat()
拼接字符串
slice()
分隔字符串, 参数为负值时,将传 入的负值与字符串的长度相加
substr()
两个参数,第一个参数是起始位置(只有一个参数代表返回当前位置到最后的所有字符),第二个参数(可选)是要返回的个数 参数为负值时,将负的第一个参数加上字符串的长度,而将负的第二个 参数转换为 0。
substring()
和slice() 一样,但是参数为负数时,会将所有参数都转换为0. - 字符串位置方法:indexOf() 和lastIndexOf() 和数组的方法类似
- 字符串大小写转换:
toLowerCase() ——转换为小写;
toUpperCase() ——转换为大写;
toLocaleLowerCase() 和 toLocaleUpperCase()方法则是针对特定地区的实现 - 字符串的模式匹配方法: match()、search()、replace()、 split()
localecompare()
这个方法比较两个字符串,并返回下列 值中的一个:
如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多数情况下是-1);
如果字符串等于字符串参数,则返回 0;
如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多数情况下是 1)。 fromCharCode()是接收一或 多个字符编码,然后将它们转换成一个字符串
- Number
Number 是与数字值对应的引用类型。要创建 Number 对象,可以在调用 Number 构造函数时向其中传递相应的数值。
Number 类型重写了 valueOf()、toLocaleString()和 toString()方法。重写后的 valueOf()方法返回对象表示的基本类型的数值,另外两个方法则返回字符串形式的数值。
除了继承的方法之外,Number 类型还提供了一些用于将数值格式化为字符串的方法。toFixed()方法会按照指定的小数位返回数值的字符串表示, toExponential()方法返回以指数表示法(也称 e 表示法)表示的数值的字符串形式。
6. 单例内置对象
内置对象即不用显式实例化内置对象,因为它们已经实例化好了。常见的内置对象包括Object、Array 和 String,这里主要介绍另外两个单例内置对象:Global 和 Math。
6.1 Global对象
Global对象不会被代码显式访问,ECMA-262规定Global对象为一种兜底对象,它所针对的是不属于任何对象的属性和方法。
事实上,不存在 全局变量 或 全局函数 这种东西。在全局作用域中定义的变量和函数都会变成Global对象的属性 。 包括isNaN()、isFinite()、parseInt()和parseFloat(),实际上都是 Global 对象的方法。除了这些,Global 对象上还有另外一些方法。
6.1.1 URL编码方法
用于编码统一资源标识符(URI),以便传给浏览器。有效的URI不能包含某些字符(比如空格)。使用URI编码方法来编码URI可以让浏览器能够理解它们,同时又以特殊的UTF-8编码替换掉所有无效字符。
编码方法:
ecnodeURI()
方法:用于对整个URI进行编码;比如 “www.wrox.com/illegal value.js”。
encodeURIComponent()
方法:用于编码URI中单独的组件,比如前面URL中的 " illegal value.js "
let uri = "http://www.wrox.com/illegal value.js#start";
// "http://www.wrox.com/illegal%20value.js#start"
console.log(encodeURI(uri)); // 空格被替换为%20
// "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.js%23start"
console.log(encodeURIComponent(uri));
encodeURI()不会编码属于URL组件的特殊字符(比如冒号、斜杠、问号、井号),而encodeURIComponent()会编码它发现的所有非标准字符。
注意: 一般来说,使用 encodeURIComponent() 比使用 encodeURI() 的频率更高,这是因为编码查询字符串参数比编码基准URI的次数更多。
与encodeURI()和encodeURIComponent()相对的是decodeURI()
方法和decodeURIComponent()
方法:
decodeURI()
方法:只对使用encodeURI()编码过的字符解码。例如,%20会被替换为空格,但%23不会被替换为井号(#),因为井号不是由encodeURI()替换的。decodeURIComponent()
方法:解码所有被encodeURIComponent()编码的字符,基本上就是解码所有特殊值。
6.1.2 eval
方法
eval()
可能是整个ECMAScript语言中最强大的了,它就是一个完整的 ECMAScript 解释器 。
eval("console.log('hi')");
`等价于
console.log("hi");
通过eval()执行的代码属于该调用所在上下文,被执行的代码与该上下文拥有相同的作用域链。定义在包含上下文中的变量可以在eval()调用内部被引用。
let msg = "hello world";
eval("console.log(msg)"); // "hello world"
也可以在eval()内部定义一个函数或变量,然后在外部代码中引用。
eval("function sayHi() { console.log('hi'); }");
sayHi();
通过eval()定义的任何变量和函数都不会被提升,这是因为在解析代码的时候,它们是被包含在一个字符串中的。只是在eval()执行的时候才会被创建。
注意:
1.严格模式下,在eval()内部创建的变量和函数无法被外部访问。同样,在严格模式下,赋值给eval也会导致错误;
2.解释代码字符串的能力虽然非常强大,但也很危险。在使用eval()时必须慎重,特别是解释用户输入内容时。因为该方法会对XSS
利用暴露出很大的攻击面。恶意用户可能插入会导致你网站或应用崩溃的代码。
6.1.3 Global对象属性
6.1.4 window 对象
浏览器将 window 对象实现为 Global 对象的代理。故所有全局作用域中声明的变量和函数都变成了 window 的属性 。
另一种获取 Global 对象的方式,如下所示:
let global = function() {
return this;
}();
本段代码创建了立即函数,返回了this的值。
当一个函数在没有明确(通过成为某个对象的方法,或者通过call()/apply() )指定this值的情况下执行时,this值等于 Global 对象。 因此,调用一个简单返回this的函数是在任何执行上下文中获取 Global 对象的通用方式。
6.2 Math
Math
对象用于保存数学公式、信息和计算,并提供了一些辅助计算的属性和方法。
Math对象上提供的计算要比直接在 JavaScript 实现的快得多,因为Math对象上的计算使用了JavaScript 引擎中更高效的实现和处理器指令。
注意:使用 Math 计算的精度会因浏览器、操作系统、指令集和硬件而异 。
6.2.1 Math对象属性
6.2.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
这两个方法可以避免使用额外的循环和if语句来确定一组数值的最大、最小值。
数组中的最大值和最小值,可以像下面这样使用扩展操作符(...
):
let values = [1, 2, 3, 4, 5, 6, 7, 8];
let max = Math.max(...values);
6.2.3 Math舍入方法
把小数值舍入为整数的4个方法:
Math.ceil()
方法:向上舍入 为最接近的整数;Math.floor()
方法:向下舍入 为最接近的整数。;Math.round()
方法:执行 四舍五入;Math.fround()
方法:返回数值最接近的 单精度(32位)浮点值。
6.2.4 Math.random()方法
Math.random()
方法返回一个0~1范围内的随机数,其中包含0但不包含1。可应用于显示随机名言或随机新闻的网页。
从一组整数中随机选择一个数:
1)公式:
number = Math.floor(Math.random() * total_number_of_choices + first_possible_value)
公式中使用了Math.floor()方法,因为Math.random()始终返回小数,即便乘以一个数再加上一个数也是小数。
2)代码:
从1~10范围内随机选择一个数,代码如下:
let num = Math.floor(Math.random() * 10 + 1);
这样就有 10 个可能的值(1~10),其中最小的值为1。
如果想选择一个2~10范围内的值,则代码如下:
let num = Math.floor(Math.random() * 9 + 2);
2~10只有9个数,所以可选总数(total_number_of_choices)是9,而最小可能的值(first_possible_value)为2。