# 引用类型
# Object 类型
创建对象:
var person = {}
// 上面等价于
var person = new Object()
var person = {
name: 'jie',
age: 18
}
// 也可以
var person = {
"name": "jie",
"age": 18,
5: true // 5 会转换为字符串
}
# Array 类型
# 创建数组
// 下面 3 种都可以
var colors = new Array('red', 'blue')
var colors = Array('red', 'blue')
var colors = ['red', 'blue']
数组的 length 属性不是只读的,可以通过设置这个属性,可以从数组的末尾移除项或向数组中添加新项:
var colors = ['red', 'blue', 'green']
colors.length = 2
alert(colors[2]) // undefined
Array 构造函数还有两个 ES6 新增的用于创建数组的静态方法: from() 和 of() 。 from() 用于将类数组结构转换为数组实例,而 of() 用于将一组参数转换为数组实例。
Array.from() 的第一个参数是一个类数组对象,即任何可迭代的结构,或者有一个 length 属性和可索引元素的结构。这种方式可用于很多场合:
// 字符串会被拆分为单字符数组
console.log(Array.from('Matt')) // ["M", "a", "t", "t"]
// 可以使用 from() 将集合和映射转换为一个新数组
const m = new Map().set(1, 2).set(3, 4)
const s = new Set().add(1).add(2).add(3).add(4)
console.log(Array.from(m)) // [[1, 2], [3, 4]]
console.log(Array.from(s)) // [1, 2, 3, 4]
// Array.from() 对现有数组执行浅复制
const a1 = [1, 2, 3, 4]
const a2 = Array.from(a1)
console.log(a1) // [1, 2, 3, 4]
console.log(a1 === a2) // false
// 可以使用任何可迭代对象
const iter = {
*[Symbol.iterator]() {
yield 1
yield 2
yield 3
yield 4
}
}
console.log(Array.from(iter)) // [1, 2, 3, 4]
// arguments 对象可以被轻松地转换为数组
function getArgsArray() {
return Array.from(arguments)
}
console.log(getArgsArray(1, 2, 3, 4)) // [1, 2, 3, 4]
// from() 也能转换带有必要属性的自定义对象
const arrayLikeObject = {
0: 1,
1: 2,
2: 3,
3: 4,
length: 4
}
console.log(Array.from(arrayLikeObject)) // [1, 2, 3, 4]
Array.from() 还接收第二个可选的映射函数参数。这个函数可以直接增强新数组的值,而无须像调用 Array.from().map() 那样先创建一个中间数组。还可以接收第三个可选参数,用于指定映射函数中 this 的值。但这个重写的 this 值在箭头函数中不适用。
const a1 = [1, 2, 3, 4];
const a2 = Array.from(a1, x => x**2);
const a3 = Array.from(a1, function(x) {return x**this.exponent}, {exponent: 2});
console.log(a2); // [1, 4, 9, 16]
console.log(a3); // [1, 4, 9, 16]
Array.of() 可以把一组参数转换为数组。这个方法用于替代在ES6之前常用的 Array.prototype.slice.call(arguments) ,一种异常笨拙的将 arguments 对象转换为数组的写法:
console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4]
console.log(Array.of(undefined)); // [undefined]
# 数组空位
使用数组字面量初始化数组时,可以使用一串逗号来创建空位(hole)。ECMAScript 会将逗号之间相应索引位置的值当成空位,ES6 规范重新定义了该如何处理这些空位。
const options = [,,,,,] // 创建包含 5 个元素的数组
console.log(options.length) // 5
console.log(options)
ES6 新增的方法和迭代器与早期 ECMAScript 版本中存在的方法行为不同。ES6 新增方法普遍将这些空位当成存在的元素,只不过值为 undefined。
const options = [1,,,,5];
for (const option of options) {
console.log(option === undefined);
}
// false
// true
// true
// true
// false
const a = Array.from([,,,]); // 使用 ES6 的 Array.from() 创建的包含 3 个空位的数组
for (const val of a) {
alert(val === undefined);
}
// true
// true
// true
alert(Array.of(...[,,,])); // [undefined, undefined, undefined]
for (const [index, value] of options.entries()) {
alert(value);
}
// 1
// undefined
// undefined
// undefined
// 5
ES6 之前的方法会忽略这个空位,但具体的行为也会因为各个方法的不同而有差异:
const options = [1, , , , 5]
// map 会跳过空位
console.log(options.map(() => 6)) // [6, empty × 3, 6]
// join() 把空位当做空字符串
console.log(options.join('-')) // 1----5
# 检测数组
if (value instanceof Array) {
// 对数组执行某些操作
}
instanceof 操作符的问题在于,他假定只有一个全局执行环境。如果网页中包含多个框架,那实际就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的 Array 构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与在第二个框架中原生创建的数组分别具有各自不同的构造函数。
解决上面的问题,可以使用 Array.isArray() 方法,来确定某个值到底是不是数组。
if (Array.isArray(value)) {
// 对数组执行某些操作
}
# 迭代器方法
在 ES6 中,Array 的原型上暴露了 3 个用于检索数组内容的方法:keys() 、values() 和 entries()。keys() 返回数组索引的迭代器,values() 返回数组元素的迭代器,而 entries() 返回索引/值对的迭代器:
const a = ['foo', 'bar', 'baz', 'qux']
// 因为这些方法都返回迭代器,所以可以将它们的内容通过 Array.from()直接转换为数组实例
const aKeys = Array.from(a.keys())
const aValues = Array.from(a.values())
const aEntries = Array.from(a.entries())
console.log(aKeys) // [0, 1, 2, 3]
console.log(aValues) // ["foo", "bar", "baz", "qux"]
console.log(aEntries) // [[0, "foo"], [1, "bar"], [2, "baz"], [3, "qux"]]
使用 ES6 的解构可以非常容易地在循环中拆分键/值对:
const a = ['foo', 'bar', 'baz', 'qux']
for (const [idx, element] of a.entries()) {
console.log(idx)
console.log(element)
}
// 0
// foo
// 1
// bar
// 2
// baz
// 3
// qux
# 复制和填充方法
ES6 新增了两个方法:批量复制方法 copyWithin(),以及填充数组方法 fill()。这两个方法的函数签名类似,都需要指定既有数组实例上的一个范围,包含开始索引,不包含结束索引。使用这个方法不会改变数组的大小。
使用 fill() 方法可以向一个已有的数组中插入全部或部分相同的值。开始索引用于指定开始填充的位置,它是可选的。如果不提供结束索引,则一直填充到数组末尾。负值索引从数组末尾开始计算。也可以将负索引想象成数组长度加上它得到的一个正索引:
const zeroes = [0, 0, 0, 0, 0]
// 用 5 填充整个数组
zeroes.fill(5)
console.log(zeroes) // [5, 5, 5, 5, 5]
zeroes.fill(0) // 重置
// 用 6 填充索引大于等于 3 的元素
zeroes.fill(6, 3)
console.log(zeroes) // [0, 0, 0, 6, 6]
zeroes.fill(0) // 重置
// 用 7 填充索引大于等于 1 且小于 3 的元素
zeroes.fill(7, 1, 3)
console.log(zeroes) // [0, 7, 7, 0, 0];
zeroes.fill(0) // 重置
// 用 8 填充索引大于等于 1 且小于 4 的元素
// (-4 + zeroes.length = 1)
// (-1 + zeroes.length = 4)
zeroes.fill(8, -4, -1)
console.log(zeroes) // [0, 8, 8, 8, 0]
fill() 会忽略超出数组边界、零长度及方向相反的索引范围:
const zeroes = [0, 0, 0, 0, 0]
// 索引过低,忽略
zeroes.fill(1, -10, -6)
console.log(zeroes) // [0, 0, 0, 0, 0]
// 索引过高,忽略
zeroes.fill(1, 10, 15)
console.log(zeroes) // [0, 0, 0, 0, 0]
// 索引反向,忽略
zeroes.fill(2, 4, 2)
console.log(zeroes) // [0, 0, 0, 0, 0]
// 索引部分可用,填充可用部分
zeroes.fill(4, 3, 10)
console.log(zeroes) // [0, 0, 0, 4, 4]
与 fill() 不同,copyWithin() 会按照指定范围浅复制数组中的部分内容,然后将它们插入到指定索引开始的位置。开始索引和结束索引则与 fill() 使用同样的计算方法:
let ints,
reset = () => ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
reset()
// 从 ints 中复制索引 0 开始的内容,插入到索引 5 开始的位置,在源索引或目标索引到达数组边界时停止
ints.copyWithin(5)
console.log(ints) // [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
reset()
// 从 ints 中复制索引 5 开始的内容,插入到索引 0 开始的位置
ints.copyWithin(0, 5)
console.log(ints) // [5, 6, 7, 8, 9, 5, 6, 7, 8, 9]
reset()
// 从 ints 中复制索引 0 开始到索引 3 结束的内容,插入到索引 4 开始的位置
ints.copyWithin(4, 0, 3)
console.log(ints) // [0, 1, 2, 3, 0, 1, 2, 7, 8, 9]
reset()
// JavaScript 引擎在插值前会完整复制范围内的值,因此复制期间不存在重写的风险
ints.copyWithin(2, 0, 6)
console.log(ints) // [0, 1, 0, 1, 2, 3, 4, 5, 8, 9]
reset()
// 支持负索引值,与 fill() 相对于数组末尾计算正向索引的过程是一样的
ints.copyWithin(-4, -7, -3)
console.log(ints) // [0, 1, 2, 3, 4, 5, 3, 4, 5, 6]
copyWithin()
// 索引过低,忽略
ints.copyWithin(1, -15, -12)
console.log(ints) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
reset()
// 索引过高,忽略
ints.copyWithin(1, 12, 15)
console.log(ints) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
reset()
// 索引反向,忽略
ints.copyWithin(2, 4, 2)
console.log(ints) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
reset()
// 索引部分可用,复制、填充可用部分
ints.copyWithin(4, 7, 10)
console.log(ints) // [0, 1, 2, 3, 7, 8, 9, 7, 8, 9]
# 转换方法
调用 valueOf() 方法返回的是数组本身,调用数组的 toString() 方法,会返回数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串。 toLocaleString() 方法经常也会返回与 valueOf() 和 toString() 方法相同的值,但也不总是如此。当调用数组的 toLocaleString() 方法时,他会创建一个数组值的以逗号分隔的字符串。而与前两个方法唯一的不同之处在于。这一次为了取得每一项的值,调用的是每一项的 toLocaleString() 方法,而不是 toString() 方法:
var person1 = {
toLocaleString: function () {
return 'Nikolaos'
},
toString: function() {
return 'Nicholas'
}
}
var person2 = {
toLocaleString: function () {
return 'Grigorios'
},
toString: function() {
return 'Grey'
}
}
var people = [person1, person2]
people.toString() // "Nicholas,Grey"
people.toLocaleString() // "Nikolaos,Grigorios"
join() 方法,如果不传入任何值,或者给他传入 undefined,则使用逗号作为分隔符。
如果数组中的某一项的值是 null 或者 undefined,那么该值在 join()、toLocaleString()、toString()、和 valueOf() 方法返回的结果中以空字符串表示。
# 栈方法
栈是一种 LIFO (Last-In-First-Out)后进先出的数据结构,也就是最新添加的项最早被删除。栈中项的插入和移除只发生在一个位置,那就是栈的顶部; ECMAScript 为数组提供了 push 和 pop 方法来实现栈的行为;
- push() 可以接收任意参数然后将他们逐个添加到数组的末尾,并返回修改后数组的长度;
- pop() 从数组的末尾移除最后一项,减少数组的 length 值,然后返回移除的项;
const colors = new Array()
let count = colors.push('red', 'green')
console.log(count) // 2
let count1 = colors.push('black')
console.log(count1) // 3
const item = colors.pop()
console.log(item) // black
# 队列方法
队列方位规则是 FIFO(First-In-First-Out,先进先出);实现这一操作的是 shift() 方法和 push() 方法;
- shift() 方法能够移除数组中的第一个项并返回该项,同时将长度减 1;
const colors = new Array()
let count = colors.push('red', 'green')
console.log(count) // 2
let count1 = colors.push('black')
console.log(count1) // 3
const item = colors.shift()
console.log(item) // red
还有一个方法 unshift() 方法,他与 shift() 方法的作用相反,他能在数组前端添加任意个项并返回新数组的长度。因此,同时使用 unshift() 和 pop() 方法,可以从相反的方向来模拟队列,也就是在数组的前端添加项,从数组的末端移除项:
const colors = new Array()
let count = colors.unshift('red', 'green')
console.log(count) // 2
let count1 = colors.unshift('black')
console.log(count1) // 3
console.log(colors) // black, red, green
const item = colors.pop()
console.log(item) // green
# 重排序方法
数组的重排序有两个方法:reverse() 和 sort():
- reverse() 反转数组项的顺序
- sort() 按升序排列数组项,也就是最小的值位于最前面,最大的值在后面,为了实现排序,sort() 方法会调用每个数据项的 toString() 转型方法,然后比较得到的字符串,以确定如何排序。即使数组中的每一项都是数值,sort() 方法比较也是字符串;
var values = [1, 2, 3]
values.reverse()
console.log(3, 2, 1)
values = [0, 1, 5, 10, 15]
values.sort()
console.log(values) // 0, 1, 10, 15, 5
sort() 方法接收一个比较函数作为参数,以便我们指定哪个值位于哪个值的前面,比较函数接收两个参数,如果第一个参数应该位于第二个之前则返回负数,如果两个参数相等则返回 0,如果第一个参数应该位于第二个之后则返回一个正数:
function compare(value1, value2) {
// values = [0, 1, 5, 10, 15]
// value1, value2 = 1, 0
// value1, value2 = 5, 1
// value1, value2 = 10, 5
// value1, value2 = 15, 10
if (value1 < value2) {
return -1
} else if (value1 > value2) {
return 1
} else {
return 0
}
}
sort() 和 reverse() 方法的返回值是经过排序后的数组
如果数组是数值类型或者其 valueOf() 方法会返回数值类型的对象类型,可以使用一个更简单的比较函数:
function compare(value1, value2) {
return value2 - value2
}
# 操作方法
- concat() 方法
这个方法会先创建当前数组的一个副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。在没有传递参数的情况下,它只是复制当前数组并返回副本。
var colors = ['red', 'green']
var clors2 = colors.concat('blue', ['yellow'])
console.log(colors) // red, green
console.log(colors2)// red, green, blue, yellow
打平数组参数的行为可以重写,方法是在参数数组上指定一个特殊的符号: Symbol.isConcatSpreadable 。这个符号能够阻止 concat() 打平参数数组。相反,把这个值设置为 true 可以强制打平类数组对象:
let colors = ["red", "green", "blue"];
let newColors = ["black", "brown"];
let moreNewColors = {
[Symbol.isConcatSpreadable]: true,
length: 2,
0: "pink",
1: "cyan"
};
newColors[Symbol.isConcatSpreadable] = false;
// 强制不打平数组
let colors2 = colors.concat("yellow", newColors);
// 强制打平类数组对象
let colors3 = colors.concat(moreNewColors);
console.log(colors); // ["red", "green", "blue"]
console.log(colors2); // ["red", "green", "blue", "yellow", ["black", "brown"]]
console.log(colors3); // ["red", "green", "blue", "pink", "cyan"]
- slice() 方法 - 不会影响原始数组
这个方法是基于当前数组中的一或多个项创建一个新数组,slice() 方法可以接收一或两个参数,即要返回项的起始和结束为止。在只有一个参数的情况下,返回从该参数指定为止开始到当前数组末尾的所有项。如果有两个参数,该方法返回起始和结束为止之前的项,不包括结束位置的项。
var colors = ['red', 'green', 'blue', 'yellow', 'purple']
var clors2 = colors.slice(1)
var colors3 = colors.slice(1, 4)
console.log(colors) // 'green', 'blue', 'yellow', 'purple'
console.log(colors2)// 'green', 'blue', 'yellow'
如果 slice() 方法的参数中有一个负数,则用数组长度加上该数来确定相应的位置;如果开始位置大于结束位置,返回空数组
- splice() 方法
可以进行删除、插入、替换操作:
- 删除:需要指定 2 个参数,要删除的第一项的位置和要删除的项数,例如 spilce(0, 2) 会删除数组中的前两项。
- 插入:需要提供 3 个参数,起始位置、0(要删除的项)、要插入的项;如果需要插入多个,可以再传入第四、五参数,以及更多的参数,例如;splice(2, 0, 'red', 'green'),从第二个位置开始插入字符串 'red','green';
- 替换:需要是哪个参数,起始位置、要删除的项数、要插入的任意数量的项。例如;splice(2, 1, 'red', 'green') 会删除数组的位置 2 的项,然后再从位置 2 开始插入字符串 'red','green';
# 位置方法
有两个方法:indexOf() 和 lastIndexOf() 方法,都接收两个参数:要查找的项,以及查找起点位置的索引(可选参数),indexOf() 是从数组头开始查找,lastIndexOf() 是从数组的末尾开始查找。
查找规则:
- 查找返回要查找项的索引;
- 如果没有查找到,返回 -1;
- 使用全等操作符进行查找;
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1]
console.log(numbers.indexOf(4)) // 3
ES7 新增了 includes 方法,他跟 indexOf() 方法一样,都是从数组的头开始查找。includes 返回布尔值,表示是否至少找到一个与指定元素匹配的项。
let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
alert(numbers.indexOf(4)); // 3
alert(numbers.lastIndexOf(4)); // 5
alert(numbers.includes(4)); // true
alert(numbers.indexOf(4, 4)); // 5
alert(numbers.lastIndexOf(4, 4)); // 3
alert(numbers.includes(4, 7)); // false
let person = { name: "Nicholas" };
let people = [{ name: "Nicholas" }];
let morePeople = [person];
alert(people.indexOf(person)); // -1
alert(morePeople.indexOf(person)); // 0
alert(people.includes(person)); // false
alert(morePeople.includes(person)); // true
可以定义断言函数进行搜索数组,断言函数接收 3 个参数:元素、索引和数组本身。其中元素是数组中当前搜索的元素,索引是当前元素的索引,而数组就是正在搜索的数组。断言函数返回真值,表示是否匹配。
find() 和 findIndex() 方法使用了断言函数。这两个方法都从数组的最小索引开始。 find() 返回第一个匹配的元素, findIndex() 返回第一个匹配元素的索引。这两个方法也都接收第二个可选的参数,用于指定断言函数内部 this 的值。
const people = [
{
name: "Matt",
age: 27
},
{
name: "Nicholas",
age: 29
}
];
alert(people.find((element, index, array) => element.age < 28)); // {name: "Matt", age: 27}
alert(people.findIndex((element, index, array) => element.age < 28)); // 0
// 找到匹配项后,这两个方法都不再继续搜索。
const evens = [2, 4, 6];
evens.find((element, index, array) => {
console.log(element);
console.log(index);
console.log(array);
return element === 4;
});
// 2
// 0
// [2, 4, 6]
// 4
// 1
// [2, 4, 6]
# 迭代方法
数组的迭代方法都接收两个参数:要在每一项上运行的函数和运行该函数的作用域对象(可选)影响 this 的值。传入这些方法中的函数会接收三个参数:当前项,项的索引,和迭代的数组。
以下方法都不会修改数组中的项
- every():对数组的每一项执行给定的函数,如果该函数对每一项都返回 true,则返回 true;
- filter():对数组的每一项执行给定的函数,返回该函数会返回 true 的项组成的数组;
- forEach():数组中的每一项执行给定的函数,该方法没有返回值;
- map():对数组的每一项执行给定的函数,返回每次函数调用的结果组成的数组;
- some():对数组的每一项执行给定的函数,如果该函数对任一项返回 true,则返回 true;
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1]
var everyResult = numbers.every((item, index, array) => {
return item > 2
})
console.log(everyResult) // false
var someResult = numbers.some((item, index, array) => {
return item > 2
})
console.log(someResult) // true
var filterResult = numbers.filter((item, index, array) => {
return item > 2
})
console.log(filterResult) // [3, 4, 5, 4, 3]
var mapResult = numbers.map((item, index, array) => {
return item > 2
})
console.log(mapResult) // [false, false, true, true, true, true, true, false, false]
var mapResult2 = numbers.map((item, index, array) => {
item > 2
})
console.log(mapResult2) // [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]
var filterResult2 = numbers.filter((item, index, array) => {
item > 2
})
console.log(filterResult2) // []
# 归并方法
归并方法 reduce() 和 reduceRight() 方法。这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。
- reducer() 方法从数组的第一项开始,逐个遍历到最后;
- reduceRight() 方法从数组的最后一项开始,向前遍历到数组第一项;
两个方法都接收两个参数:一个在每一项上调用的函数和作为归并基础的初始值(可选),传入这两个方法的函数都会接收 4 个参数:前一个值、当前值、项的索引和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是驻足的第一项,第二个参数就是数组的第二项。
var values = [1, 2, 3, 4, 5]
var sum = values.reduce((prev, cur, index, array) => {
return prev + cur
})
console.log(sum)
# Date 类型
创建一个日期对象:
var now = new Date() // 不传参数,自动获取当前日期和时间
如果需要根据指定的时期和时间创建对象,必须传入表示该日期的毫秒数,为了简化这个过程,ECMAScript 提供了两个方法:Date.parser() 和 Date.UTC():
- Date.parser() 方法
// 返回自定义时间戳
Date.parse('2020/08/14')
// 返回当前时间的事件戳
Date.parse(new Date())
如果传入 Date.parser() 方法的字符串不能表示日期,那么返回 NaN,实际上,如果直接将表示日期的字符串传递给 Date 构造函数,也会在后台调用 Date.parser() 方法。
- Date.UTC() 方法
他需要的参数分别是年份、基于 0 的月份(一月是 0)、月中的哪一天(1-31)、小时数(0-23)、分钟、秒以及毫秒数。这些参数中,只有前两个参数是必须的:
const utcDate1 = new Date(Date.UTC(2020, 7, 14))
console.log(utcDate1.toUTCString()) // Fri, 14 Aug 2020 00:00:00 GMT
// 上面代码等同于
const date = new Date(2020, 7, 14)
- Date.now()
该方法返回调用这个方法时的日期和时间的毫秒数。
# 继承的方法
Date 同样具有 toLocaleString() 、toString()、valueOf() 方法。
- toLocaleString() 按照与浏览器设置的地区相适应的格式返回日期和时间。
- toString() 返回带有时区信息的日期和时间,其中时间一般以军用时间(即小时的范围是 0-23)表示。
上面两种方法对于不同的浏览器返回的结果不同
- valueOf() 不返回字符串,返回日期的毫秒表示。因此,可以使用比较操作符来比较日期值。
var data1 = new Date(2020, 7, 14)
var data2 = new Date(2020, 7, 15)
console.log(data1 < data2) // true
# 日期的格式化
- toDateString() 以特定于实现的格式显示星期几、月、日和年;
- toTimeString() 以特定于实现的格式显示时、分、秒和时区;
- toLocaleDateString() 以特定于地区的格式显示星期几、月、日和年;
- toLocaleTimeString() 以特定于实现的格式显示时、分、秒;
- toUTCString() 以特定于实现的格式完整的 UTC 日期;
上面的格式方法的输出因浏览器不同也是不一样的。
# 日期/时间组件方法
- getTime():返回表示日期的毫秒数;与 valueOf() 方法返回的值相同。
- setTime(毫秒):以毫秒数设置日期,会改变整个日期。
- getFullYear():取得 4 位数的年份。
- getUTCFullYear():返回 UTC 日期的 4 位数年份。
- setFullYear(年):设置日期的年份。传入的年份值必须是4位数字。
- setUTCFullYear(年):设置 UTC 日期的年份。传入的年份值必须是4位数字。
- getMonth():返回日期中的月份,其中 0 表示一月,11 表示十二月。
- getUTCMonth():返回 UTC 日期中的月份,其中 0 表示一月,11表示十二月。
- setMonth(月):设置日期的月份(0-11)。
- setUTCMonth(月):设置 UTC 日期的月份(0-11)。
- getDate():返回日期月份中的天数(1-31)。
- getUTCDate():返回 UTC 日期月份中的天数(1-31)。
- setDate(日):设置日期月份中的天数(1-31)。
- setUTCDate(日):设置 UTC 日期月份中的天数(1-31)。
- getDay():返回日期中星期的星期几(0 表示星期日,6 表示星期六)。
- getUTCDay():返回 UTC 日期中星期的星期几(0 表示星期日,6 表示星期六)。
- getHours():返回日期中的小时数(0-23)。
- getUTCHours():返回 UTC 日期中的小时数(0-23)。
- getMinutes():返回日期中的分钟数(0-59)。
- getUTCMinutes():返回 UTC 日期中的分钟数(0-59)。
- setMinutes(分):设置日期中的分钟数。
- setUTCMinutes(分):设置 UTC 日期中的分钟数。
- getSeconds():返回日期中的秒数(0-59)。
- getUTCSeconds():返回 UTC 日期中的秒数(0-59)。
- setSeconds(秒):设置日期中的秒数。
- setUTCSeconds(秒):设置 UTC 日期中的秒数。
- getMilliseconds():返回日期中的毫秒数。
- getUTCMilliseconds():返回 UTC 日期中的毫秒数。
- setMilliseconds(毫秒):设置日期中的毫秒数。
- setUTCMilliseconds(毫秒):设置 UTC 日期中的毫秒数。
- getTimezoneOffset():返回本地时间与 UTC 时间相差的分钟数。
# RegExp 类型
# 创建正则表达式
每个正则表达式都可带有一个或者多个标志,用来标明正则表达式的行为。正则表达式的匹配模式支持下面的 3 个标志:
- g:表示全局模式,也就是说模式将被应用到所有字符串。
- i:表示不区分大小写模式。
- m:表示多行模式。
一个正则表达式就是一个模式与上面三个标志的组合体。
// 匹配字符串中所有 at 的实例
var pattern1 = /at/g
// 匹配第一个 bat 或者 cat ,不区分大小
var pattern2 = /[bc]at/i
// 匹配所有以 at 结尾的 3 个字符的组合,不区分大小写
var pattern3 = /.at/gi
模式中使用的所有元字符都必须转义,正则表达式中的元字符包括: 这些元字符在正则表达式中都有一种或者多种特殊用途,因此如果想要匹配字符串中包含的这些字符,就必须对他们进行转义;
( [ { \ ^ $ | ) ? * + . ] }
// 匹配第一个 bat 或者 cat ,不区分大小
var pattern2 = /[bc]at/i
// 匹配第一个[bc] at, 不区分大小
var pattern3 = /\[bc\]at/i
// 匹配所有以 at 结尾的 3 个字符的组合,不区分大小写
var pattern4 = /.at/gi
// 匹配所有 .at ,不区分大小写
var pattern5 = /\.at/gi
也可以使用 RegExp 构造函数创建正则对象:第一个参数是要匹配的字符串模式,另一个是可选的标志字符串。 下面的 pattern1 和 pattern2 是等价的。
var pattern1 = /[bc]at/i
var pattern2 = new RegExp('[bc]at', 'i')
由于 RegExp 构造函数的模式都是字符串,所以在某些情况下需要对字符串进行双重转义,所有元字符都必须双重转义,那些转义过的字符也是如此。
字面量模式 | 等价的字符串 |
---|---|
/[bc]at/ | "\[bc\]at" |
/.at/ | "\.at" |
/name/age/ | "name\/age" |
/\d.\d{1,2}/ | "\d.\d{1,2}" |
/\w\hello\123/ | "\w\\hello\\123" |
# RegExp 实例属性
RegExp 的每个实例都具有下面的属:
- global:布尔值,表示是否设置了 g 标志
- ignotrCase: 布尔值,表示是否设置了 i 标志
- lastIndex:整数,表示开始搜索下一个匹配项的字符位置,从 0 算起
- multiline:布尔值,表示是否设置了 m 标志
- source:正则表达式的字符串表示,按照字面量形式而非插入构造函数中的字符串模式返回
var pattern1 = /\[bc\]at/i
console.log(pattern1.lastIndex) // 0
console.log(pattern1.source) // \[bc\]at
var pattern2 = new RegExp("\\[bc\\]", "i")
console.log(pattern2.souce) // \[bc\]
# RegExp 实例方法
- exec():接收一个参数就是要应用模式的字符串,然后返回包含第一个匹配项信息的数组,或者在没有匹配项的情况下返回 null; 返回的数组有两个额外的属性:index 和 input,index 表示匹配项在字符串中的位置,input 表示应用正则表达式的字符串。在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串(如果模式中没有捕获组,则该数组只包含一项):
var text = 'mom and dad and baby'
var pattern = /mom( and dad( and baby)?)?/gi
var 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
exec() 方法,即使在模式中设置了全局标志,它每次也只会返回一个匹配项。在不设置全局标志的情况下,在同一个字符串上多次调用 exec() 将始终返回第一个匹配项的信息。而在设置全局标志的情况下,每次调用 exec() 则都会在字符串中继续查找新匹配项:
var text = 'cat, bat, sat, fat'
var pattern1 = /.at/
var matches = pattern1.exec(text)
console.log(matches.index) // 0
console.log(matches[0]) // cat
console.log(pattern1.lastIndex) // 0
matches = pattern1.exec(text)
console.log(matches.index) // 0
console.log(matches[0]) // cat
console.log(pattern1.lastIndex) // 0
var pattern2 = /.at/g
var matches = pattern2.exec(text)
console.log(matches.index) // 0
console.log(matches[0]) // cat
console.log(pattern2.lastIndex) // 3
matches = pattern2.exec(text)
console.log(matches.index) // 5
console.log(matches[0]) // bat
console.log(pattern2.lastIndex) // 8
这里需要注意模式的 lastIndex 属性的变化,在全局模式下,lastIndex 的值在每次调用 exec() 后都会增加,而在非全局模式下则会保持不变。
- test() 方法:在模式与该参数匹配的情况下返回 true;
var text = '000-00-0000'
var pattern = /\d{3}-\d{2}-\d{4}/
if (pattern.test(text)) {
console.log('匹配成功')
}
- toLocaleString() 和 toString() 方法:返回正则表达式的字面量:
var 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
# RegExp 构造函数属性
长属性名 | 短属性名 | 说 明 |
---|---|---|
input | $_ | 最近一次要匹配的字符串。 |
lastMatch | $& | 最近一次的匹配项 |
lastParen | $+ | 最近一次匹配的捕获组 |
leftContext | $` | input 字符串中 lastMatch 之前的文本 |
multiline | $* | 布尔值,表示是否所有表达式都使用多行模式 |
rightContext | $' | input 字符串中 lastMatch 之后的文本 |
var text = 'this has been a short summer'
var 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
console.log(RegExp.multiline) // false
}
# 函数声明与函数表达式
解析器在向执行环境中加载数据时,对函数声明和函数表达式处理是不一样的。解析器会率先读取函数声明,并使其在执行任何代码之前可用,至于函数表达式,则必须等到解析器执行到他所在的代码行,才会真正被解析执行:
console.log(sum) // 函数--函数声明会提升
var sum = '1'
function sum(num1, num2) {
return num1 + num2
}
// 换成下面的声明方式就会报错
console.log(sum(10, 10))
var sum = function (num1, num2) {
return num1 + num2
}
# 函数的内部属性
在函数内部,有两个特殊的对象:arguments 和 this;arguments 是一个类数组对象,包含传入函数中的所有参数,arguments 还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。
- arguments 对象
如下一个阶乘函数:
function factorial(num) {
if (num <= 1) {
return 1
} else {
return num * factorial(num - 1)
}
}
定义阶乘需要递归算法,上面的代码有缺陷,如果一旦函数名变了,还得修改对应的递归函数名,这个函数的执行与函数名 factorial 紧紧耦合在一起的。我们可以借助 callee 来消除这种耦合现象:
function factorial(num) {
if (num <= 1) {
return 1
} else {
return num * arguments.callee(num - 1)
}
}
这样不管用什么函数名都可以使用:
var tureFactorial = factoriac
factorial = function() {
return 0
}
console.log(tureFactorial(5)) // 120
console.log(factorial(5)) // 0
- this 对象
this 引用的是函数执行的环境对象。当在网页的全局作用域中调用函数时,this 对象引用的就是 Window;
- caller 属性
这个属性保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,他的值为 null:
因为 outer() 调用了 inner() ,所以 inner.caller 就指向 outer(),也可以通过 argument.callee.caller 来访问。
function outer() {
inner()
}
function inner() {
console.log(inner.caller)
}
outer() // ƒ outer() { inner() }
当函数在严格模式下运行,访问 arguments.callee 会导致错误, ECMAScript 5 还定义了 arguments.caller 属性,但在严格模式下也会访问也会报错。在非严格模式下,这个属性始终是 undefined。严格模式还有一个限制:不能为函数的 caller 属性赋值,否则会导致报错;
# 函数属性和方法
每个函数都包含两个属性:length 和 prototype:
- length:表示函数希望接收的命名参数的个数。
- prototype:是保存所有实例方法,也就是函数的原型对象。该属性是不可枚举的,因此使用 for ... in 无法访问。
function sum(sum1, sum2) {
return sum1 + sum2
}
console.log(sum.length) // 2
每个函数都有两个非继承而来的方法:apply() 和 call() 方法。两个方法都是设置函数体内 this 的值:
- apply():接收两个参数,一个是 this 的指向对象,另一个是参数数组(可以是 array 的实例,也可以是 arguments 对象);
- call():与 apply() 方法的作用相同,第一个参数是 this 对象,其余参数直接传递给函数。
- bind():这个方法会创建一个函数实例,其 this 值会绑定到传给 bind() 函数的值。
在严格模式下,未指定环境对象而调用函数,则 this 值不会转型为 window,除非明确把函数添加到某个对象或者调用 apply() 或 call() ,否则 this 值将是 undefined。
function sum(num1, num2) {
return num1 + num2
}
// apply()
function applySum(num1, num2) {
return sum.apply(this, [num1, num2])
// 或者
return sum.apply(this, arguments)
}
// this 为 window 对象
console.log(applySum(1, 2))
// call()
function callSum(num1, num2) {
return sum.call(this, num1, num2)
}
console.log(callSum(1, 2))
// bind()
window.color = 'red'
var o = {
color: 'blue'
}
function sayColor() {
console.log(this.color)
}
var objectSayColor = sayColor.bind(o)
objectSayColor() // blue
上面三个方法继承的 toLocaleString() 和 toString() 方法都始终返回函数的代码。valueOf() 也是返回函数代码。
# 基本包装类型
一般我们调用基本类型方法(基本类型不是对象,但是有包装类型)的时候其实是经过下列步骤:
比如:
var s1 = 'some text'
var s2 = s1.substring(2)
执行步骤:
- 创建 String 类型的一个实例;
- 在实例上调用指定的方法;
- 销毁这个实例;
可以将上面三个步骤写成下面代码:
var s1 = new String('some text')
var s2 = s1.substring(2)
s1 = null
引用类型与基本包装类型的主要区别就是对象的生存期。使用 new 操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。所以我们不能在运行的时候为基本类型值添加属性和方法。
Object 构造函数也会像工厂方法一样,会根据传入值的类型返回相应基本包装类型的实例:
var obj = new Object('some text')
console.log(obj instanceof String) // true
要注意的是,使用 new 调用基本包装类型的构造函数,与直接调用同名的转型函数是不一样的:
var value = '12'
var number = Number(value) // 转型函数
console.log(typeof number) // number
var obj = new Number(value) // 构造函数
console.log(typeof obj) // object
# Boolean 对象
下面代码 new Boolean(false) 返回的是 true,是因为布尔表达式中的所有对象都会被转换为 true,new Boolean(false) 创建出来的是一个对象。
var falseObject = new Boolean(false)
var result = falseObject && true
console.log(result) // true
var falseValue = false
result = falseValue && true
console.log(result) // false
console.log(typeof falseObject) // object
console.log(typeof falseValue) // boolean
console.log(falseObject instanceof Boolean) // true
console.log(falseValue instanceof Boolean) // false
# Number 类型
- toFixed() 方法会按照指定的小数位返回数值的字符串表示。如果指定位数不够会补零,如果多余通过四舍五入进行取值;
- toString() 方法可以传递一个表示基数的参数,告诉他返回多少进制数值的字符串格式。
- toExponential() 方法返回以指数表示法(也称 e 表示法)表示的数值的字符串形式;也接收一个参数,而且该参数同样也是指定输出结果中的小数位数。
- toPrecision() 方法可能会返回固定大小格式,也可能返回指数格式,具体规则是看哪种格式最合适。这个方法接收一个参数,即表示数值的所有数字的位数(不包括指数部分)。实际上,他会根据处理的数值决定调用 toFixed() 还是调用 toExponential()。
var num = 10
console.log(num.toString(2)) // 1010
console.log(num.toFixed(2)) // 10.00
num = 10.005
console.log(num.toFixed(2)) // 10.01
var num = 10
console.log(num.toExponential(1)) // 1.0e+1
var num = 99
console.log(num.toPrecision(1)) // 1e+2 一位数无法精确表示 99,因此向上舍入为 100
console.log(num.toPrecision(2)) // 99
console.log(num.toPrecision(3)) // 99.0
# String 类型
# 字符方法
用于访问字符串中特定字符的方法:chatAt() 和 chartCodeAt()。这两个方法接收一个参数,即基于 0 的字符位置。
- chatAt() 返回指定位置单字符字符串的形式;
- chartCodeAt() 返回指定位置字符编码;
var stringValue = 'hello world'
console.log(stringValue.chatAt(1)) // e
console.log(stringValue.charCodeAt(1)) // 101
// 可以通过方括号加数字索引来访问字符串中特定字符
console.log(stringValue[1]) // e
# 字符串操作方法
- concat() 用于将一或多个字符串拼接起来,返回拼接得到的新字符串;可以接收任意多个参数,进行拼接;
var stringValue = 'hello '
var result = stringValue.concat('world', '!')
console.log(result) // hello world!
console.log(stringValue) // hello
基于字符串创建新字符串的方法:slice() 、substr() 和 substring();这三个方法都返回被操作字符串的一个子字符串,而且都接收一个或者两个参数。 第一个参数指定字符串的开始位置,第二个字符标志子字符串到哪里结束。
- slice() 和 subString() 的第二个参数指定的是子字符串最后一个字符后面的位置。
- subStr() 方法的第二个参数指定的则是返回的字符个数。
这三个方法不会修改原字符串 如果没有给这些方法传递第二个参数,则将字符串的末尾作为结束位置。
var 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 wo
console.log(stringValue.substring(3, 7)) // lo wo
console.log(stringValue.substr(3, 7)) // lo worl
如果传递给这些方法的参数是负值:
- slice():会将传入的负值与字符串的长度相加,如果结果还是负值,则返回原字符串;如果第一个参数的结果根据前面计算完还是负值,第二个结束位置是合适的,那么返回结果是将第一个参数为 0 进行截取的。第一个参数合适,不能大于第二个参数,否则返回空字符串;
- substr():会将负的第一个参数加上字符串的长度,而将负的第二个参数转换为 0;
- substring():会将所有的负值转换为 0;
# 字符串位置方法
两个方法都是从一个字符串中搜索给定的子字符串。然后返回字符串的位置,如果没有找到该子字符串则返回 -1。如果搜索的字符串只出现过一次,那么两个返回同样的结果。这两个方法可以传第二个参数,用于指定从哪个位置开始进行搜索。
- indexOf():从字符串的开头向后找;
- laseIndexOf():从字符串的末尾向前找;
var stringValue = 'hello world'
console.log(stringValue.indexOf('o')) // 4
console.log(stringValue.lastIndexOf('o')) // 7
# trim() 方法
返回一个原始字符串的副本,用于删除字符串前后的空格;
# 字符串大小写转换
var stringValue = 'hello world'
console.log(stringValue.toUpperCase()) // HELLO WORLD
console.log(stringValue.toLowerCase()) // hello world
# 字符串的模式匹配方法
- match() 方法:本质上调用 RegExp 的 exec() 方法相同;他只接受一个参数,要么是一个正则表达式,要么是一个 RegExp 对象。
var text = 'cat, bat, sat, fat'
var pattern = /.at/
// 与 pattern.exec(text) 相同
var matches = text.match(pattern)
console.log(matches.index) // 0
console.log(matches[0]) // 'cat'
console.log(pattern.lastIndex) // 0
- search() 方法:参数是由字符串或 RegExp 对象指定的一个正则表达式。search() 方法返回字符串中第一个匹配项的索引,如果没有找,返回 -1,而且该方法始终是从字符串开头向后查找模式。
var text = 'cat, bat, sat, fat'
var pos = text.search(/at/)
console.log(pos)
- replace() 方法:替换字符串操作的方法,这个方法接收两个参数,第一个参数可以是一个 RegExp 对象或者一个字符串(这个字符串不会被转换为正则表达式),第二个参数可以是一个字符串或者一个函数。如果第一个参数是一个字符串,那么直会替换第一个子字符串,要想替换所有子字符串,唯一的办法就是提供一个正则表达式,而且要指定全局(g)标志:
var text = 'cat, bat, sat, fat'
var 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
如果第二个参数是字符串,可以使用一些特殊的字符序列,将正则表达式操作得到的值插入到结果字符串中:
字符序列 | 替换文本 |
---|---|
$$ | $ |
$& | 匹配整个模式的子字符串。与 RegExp.lastMatch 的值相同 |
$' | 匹配的子字符串之前的子字符串,与 RegExp.leftContext 的值相同 |
$` | 匹配的子字符串之后的子字符串,与 RegExp.rightContext 的值相同 |
$n | 匹配第 n 个捕获组的子字符串,其中 n 等于 0 ~ 9 ,例如 $1 是匹配第一个捕获组的子字符串,$2 是匹配第二个捕获组的子字符串,以此类推,如果正则表达式中没有定义捕获组,则使用空字符串 |
$nn | 匹配第 nn 个捕获组的子字符串,其中 nn 等于 01 ~ 99 ,例如 $01 是匹配第一个捕获组的子字符串,$02 是匹配第二个捕获组的子字符串,以此类推,如果正则表达式中没有定义捕获组,则使用空字符串 |
var text = 'cat, bat, sat, fat'
var result = text.replace(/(.at)/g, 'world ($1)')
console.log(result) // world (cat), world (bat), world (sat), world (fat)
replace() 方法的第二个参数也可以是一个函数。在只有一个匹配项(即与模式匹配的字符串)的情况下,会向这个函数传递 3 个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串。
下面是该函数的参数:
变量名 | 代表的值 |
---|---|
match | 匹配的子串。(对应于上述的$&。) |
p1,p2, ... | 假如replace()方法的第一个参数是一个RegExp 对象,则代表第n个括号匹配的字符串。(对应于上述的$1,$2等。)例如,如果是用 /(\a+)(\b+)/ 这个来匹配,p1 就是匹配的 \a+,p2 就是匹配的 \b+。 |
offset | 匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是 'abcd',匹配到的子字符串是 'bc',那么这个参数将会是 1) |
string | 被匹配的原字符串。 |
NamedCaptureGroup | 命名捕获组匹配的对象;(精确的参数个数依赖于 replace() 的第一个参数是否是一个正则表达式(RegExp)对象,以及这个正则表达式中指定了多少个括号子串,如果这个正则表达式里使用了命名捕获, 还会添加一个命名捕获的对象) |
当匹配执行后,该函数就会执行。 函数的返回值作为替换字符串。 另外要注意的是,如果第一个参数是正则表达式,并且其为全局匹配模式,那么这个方法将被多次调用,每次匹配都会被调用。
function replacer(match, p1, p2, p3, offset, string) {
// p1 is nondigits, p2 digits, and p3 non-alphanumerics
return [p1, p2, p3].join(' - ');
}
var newString = 'abc12345#$*%'.replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
console.log(newString); // abc - 12345 - #$*%
- split()方法:分隔符可以是一个字符串,也可以是一个 RegExp 对象(这个方法不会将字符串看成正则表达式)。他还可以接受第二个可选参数,用于指定数组的大小。
var colorText = 'red,blue,green,yellow'
var colors1 = colorText.split(',', 2) // ["red", "blue"]
var colors2 = colorText.split('/[^\,]+/') // ["red,blue,green,yellow"]
localeCompare() 方法:返回一个数字来指示一个参考字符串是否在排序顺序前面或之后或与给定字符串相同。
当 引用字符串 在 比较字符串 前面时返回 -1
当 引用字符串 在 比较字符串 后面时返回 1
相同位置时返回 0
fromCharCode() 方法:返回由指定的 UTF-16 代码单元序列创建的字符串。由于 fromCharCode() 是 String 的静态方法,所以应该像这样使用:String.fromCharCode(),而不是作为你创建的 String 对象的方法。
'a'.localeCompare('c')
// -2 or -1 (or some other negative value)
'check'.localeCompare('against')
// 2 or 1 (or some other positive value)
'a'.localeCompare('a');
// 0
console.log(String.fromCharCode(189, 43, 190, 61)) // "½+¾="
# 单体内置对象
Global 和 Math 对象。
# Global 对象
# URI 编码方法
使用 UTF-8 编码替换所有无效字符
- encodeURI 主要用于整个 URI;例如:http://www.wrox.com/illegal valur.html;他不会对本身属于 URI 的特殊字符进行编码,例如冒号、正斜杠、问号、井号
- encodeURIComponent() 主要用于对 URI 中的某一段,例如 illegal valur.html;会对任何非标准的字符进行编码
var uri = 'http://www.wrox.com/illegal valur.html'
console.log(encodeURI(uri)) // "http://www.wrox.com/illegal%20valur.html"
console.log(encodeURIComponent(uri)) // "http%3A%2F%2Fwww.wrox.com%2Fillegal%20valur.html"
与上面两个方法对应的是 decodeURI() 和 decodeURIComponent() 方法。对应进行解码。
# eval() 方法
- 被执行的代码具有与该执行环境相同的作用域链。这就意味着通过 eval() 执行的代码可以引用在包含环境中定义的变量。
- 在 eval() 中创建的任何变量或函数都不会被提升,因为在解析代码的时候,他们被包含在一个字符串中,他们只在 eval() 执行的时候创建。
- 在严格模式下,在外部访问不到 eval() 中创建的任何变量或函数。
# window 对象
在 web 浏览器中,将这个全局对象(GLobal)作为 window 对象的一部分加以实现的。
# Math 对象
- max() 以及 min() 方法,确定一组数中最大最小值:Math.max(3, 54, 32) 如果要查找数组中的最大或者最小值:
var values = [1, 2, 3, 4, 55, 33, 2]
var max = Math.max.apply(Math, values)
# 舍入方法
- Math.ceil() 执行向上舍入,即他总是将数值向上舍入为最接近的正数
- Math.floor() 执行向下舍入,即他总是将数值向下舍入为最接近的正数
- Math.round() 执行标准舍入,即他总是将数值四舍五入为最接近的正数
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.floor(25.9)) // 25
console.log(Math.floor(25.5)) // 25
console.log(Math.floor(25.1)) // 25
# random() 方法
返回大于等于 0 小于 1 的一个随机数。
console.log(Math.floor(Math.random() * 10 + 1)) // 1 ~ 10 的数字