1.Number.isInteger()
判断一个值是否为整数,在js内部中整数耦合浮点数是同样的存储方法,所以3和3.0被认为是同一个值。
Number.isInteger(25.1) // false
Number.isInteger("15") // false
Number.isInteger(true) // false
Number.isInteger(25) // true
Number.isInteger(25.0) // true
2.Math对象的扩展
2.1Math.trunc()用于去除一个数的小数部分,返回整数部分。
Math.trunc(4.9)
4
Math.trunc(-4.9)
-4
Math.trunc('123.78')
123
对于空置和无法截取整数的值,返回NaN
Math.trunc('fff')
NaN
2.2Math.sign()
用来判断一个数到底是正数,负数还是0,它会返回五种值:
返回+1,参数为正数;
返回-1,参数为负数;
返回0,参数为0;
返回-0,参数为-0;
返回NaN,其他值;
Math.sign(99);
1
Math.sign(0)
0
Math.sign(-2)
-1
Math.sign('999')
1
Math.sign('ff')
NaN
2017/06/06
3.数组
3.1Array.from()方法用于将两类对象转为真正的数组:类似数组的对象和
可遍历的对象。
类似数组的对象测试的时候报错,在这里不记。
扩展运算符(...)也可以将某些数据结构转为数组。
扩展运算符背后调用的是遍历器接口(Symbol.iterator
),如果一个对象没有部署这个接口,就无法转换。Array.from
方法还支持类似数组的对象。所谓类似数组的对象,本质特征只有一点,即必须有length
属性。因此,任何有length
属性的对象,都可以通过Array.from
方法转为数组,而此时扩展运算符就无法转换。
Array.from({ length: 3 });
// [ undefined, undefined, undefined ]
Array.from()
可以将各种值转为真正的数组,并且还提供map
功能。这实际上意味着,只要有一个原始的数据结构,你就可以先对它的值进行处理,然后转成规范的数组结构,进而就可以使用数量众多的数组方法。
Array.from({ length: 2 }, () => 'jack')
// ['jack', 'jack']
3.2 Array.of()
Array.of
方法用于将一组值,转换为数组。
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
这个方法的主要目的,是弥补数组构造函数Array()
的不足。因为参数个数的不同,会导致Array()
的行为有差异。
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
上面代码中,Array
方法没有参数、一个参数、三个参数时,返回结果都不一样。只有当参数个数不少于2个时,Array()
才会返回由参数组成的新数组。参数个数只有一个时,实际上是指定数组的长度。
Array.of
基本上可以用来替代Array()
或new Array()
,并且不存在由于参数不同而导致的重载。它的行为非常统一。
Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]
Array.of
总是返回参数值组成的数组。如果没有参数,就返回一个空数组。
3.3 数组实例的copyWithin()
数组实例的copyWithin
方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。
Array.prototype.copyWithin(target, start = 0, end = this.length)
它接受三个参数。
- target(必需):从该位置开始替换数据。
- start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
这三个参数都应该是数值,如果不是,会自动转为数值。
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
3.4 find() 和 findIndex()
find()用于找出第一个符合条件的数组成员,它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合的,则返回undefined.
[1, 4, -5, 10].find((n) => n < 0)
// -5
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
findeIndex()返回第一个符合条件的数组成员的索引值,如果所有成员都不符合条件,则返回-1.
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
这两个方法都可以接受第二个参数,用来绑定回调函数的this
对象。
3.4 fill( )
fill()使用给定值,填充一个数组。
['a','b','c'].fill(7)
//[7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
上面代码表明,fill
方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去。
fill
方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
3.5 entries(),keys()和values()
entries()是对索引的遍历
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
values() 是对键值得遍历
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
entries()是对键值对得遍历
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
如果不使用for...of
循环,可以手动调用遍历器对象的next
方法,进行遍历。
let letter = ['a', 'b', 'c'];
let entries = letter.entries();
console.log(entries.next().value); // [0, 'a']
console.log(entries.next().value); // [1, 'b']
console.log(entries.next().value); // [2, 'c']
3.5 includes() 返回一个布尔值,判断某个数组是否包含给定的值。
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, NaN].includes(NaN); // true
该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
indexOf
方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于-1,表达起来不够直观。二是,它内部使用严格相等运算符(===)进行判断,这会导致对NaN
的误判。
[NaN].indexOf(NaN)
// -1
includes
使用的是不一样的判断算法,就没有这个问题。
[NaN].includes(NaN)
// true
函数
4.1函数参数的默认值
es6允许为函数的参数设置默认值。
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
function Point(x = 0, y = 0) {
this.x = x;
this.y = y;
}
var p = new Point();
p // { x: 0, y: 0 }
参数变量是默认声明的,所以不能用let或者const再次声明
function foo(x = 5) {
let x = 1; // error
const x = 2; // error
}
使用参数默认值时,函数不能有同名参数。
function foo(x, x, y = 1) {
// ...
}
// SyntaxError: Duplicate parameter name not allowed in this context
另外,一个容易忽略的地方是,如果参数默认值是变量,那么参数就不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。
let x = 99;
function foo(p = x + 1) {
console.log(p);
}
foo() // 100
x = 100;
foo() // 101
4.2 参数默认值的位置
通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。
// 例一
function f(x = 1, y) {
return [x, y];
}
f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 报错
f(undefined, 1) // [1, 1]
// 例二
function f(x, y = 5, z) {
return [x, y, z];
}
f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 报错
f(1, undefined, 2) // [1, 5, 2]
上面代码中,有默认值的参数都不是尾参数。这时,无法只省略该参数,而不省略它后面的参数,除非显式输入undefined
。
如果传入undefined
,将触发该参数等于默认值,null
则没有这个效果。
function foo(x = 5, y = 6) {
console.log(x, y);
}
foo(undefined, null)
// 5 null
4.3 函数的 length 属性
返回没有指定默认值得参数个数。
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
如果默认值参数不是未参数,那么length属性也不再计入后面的参数
(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1
4.4 rest参数
rest参数(...变量名),用于获取函数的多余参数,这样就不需要arguments对象了。rest参数搭配的变量是一个数组,该变量经多余的参数放入数组中。
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
但是,rest参数之后不能再有其他参数(只能是最后一个参数),否则会报错。
function f(a,...b,c){
return c;
}
f(1,[2,3],8);//报错
函数的length属性,不包括rest参数。
(function (a){}).length;
1
(function(...a){}).length;
0
(function(a,...b){}).length;
1
4.5扩展运算符
扩展运算符是三个点(...),和rest参数的作用相反,它将一个参数转为用逗号分隔的参数。
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
...主要用于函数的调用。
function add(x, y) {
return x + y;
}
var numbers = [4, 38];
add(...numbers) // 42
替代数组的apply方法
扩展运算符可以展开数组,所以不需要apply方法,直接将数组转为普通参数
apply方法:
function f(x,y,z){
var a;
return a = x+y+z;
}
var args = [0,1,2];
f.apply(null,args);
3
扩展运算符:
function f(x,y,z){
var a;
return a = x+y+z;
}
var args = [9,1,2];
f(...args)
12
下面是扩展运算符取代apply
方法的一个实际的例子,应用Math.max
方法,简化求出一个数组最大元素的写法。
Math.max.apply(null,[14,3,77]);
77
Math.max(...[14,3,77])
77
Math.max(14,3,77)
77
通过push
函数,将一个数组添加到另一个数组的尾部。
// ES5的写法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);
// ES6的写法
var bb1 = [7,8,9];
var bb2 = [3,4,5];
bb1.push(...bb2);
bb1
[7, 8, 9, 3, 4, 5]
扩展运算符的应用
1.合并数组
扩展运算符提供了数组合并的新写法
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
// ES5的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
2.字符串,将字符串转为数组。
[...'hello']
// [ "h", "e", "l", "l", "o" ]
3.name 属性
函数的name属性,返回该函数的函数名。
function foo() {}
foo.name // "foo"
const bar = function baz() {};
// ES5
bar.name // "baz"
// ES6
bar.name // "baz"
4.6箭头函数 (=>)
var f = v => v; 等于
var f = function (v){
return v;
};
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return
语句返回。
var sum = (num1, num2) => { return num1 + num2; }
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号。
var getTempItem = id => ({ id: id, name: "Temp" });
使用注意点
箭头函数有几个使用注意点。
(1)函数体内的this
对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new
命令,否则会抛出一个错误。
(3)不可以使用arguments
对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield
命令,因此箭头函数不能用作 Generator 函数。
上面四点中,第一点尤其值得注意。this
对象的指向是可变的,但是在箭头函数中,它是固定的。
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42