1.1 let 和 const命令
在ES6中,我们通常实用 let
表示变量,const
表示常量,并且 let
和 const
都是块级作用域,且在当前作用域有效不能重复声明。
1.1.1 let 命令
let
命令的用法和 var
相似,但是 let
只在所在代码块内有效。
基础用法:
-
{
-
let a = 1;
-
let b = 2;
-
}
-
复制代码
并且 let
有以下特点:
- 不存在变量提升:
在ES6之前,我们var
声明一个变量一个函数,都会伴随着变量提升的问题,导致实际开发过程经常出现一些逻辑上的疑惑,按照一般思维习惯,变量都是需要先声明后使用。
-
// var
-
console.log(v1); // undefined
-
var v1 = 2;
-
// 由于变量提升 代码实际如下
-
var v1;
-
console.log(v1)
-
v1 = 2;
-
// let
-
console.log(v2); // ReferenceError
-
let v2 = 2;
-
复制代码
- 不允许重复声明:
let
和const
在相同作用域下,都不能重复声明同一变量,并且不能在函数内重新声明参数。
-
// 1. 不能重复声明同一变量
-
// 报错
-
function f1 (){
-
let a = 1;
-
var a = 2;
-
}
-
// 报错
-
function f2 (){
-
let a = 1;
-
let a = 2;
-
}
-
// 2. 不能在函数内重新声明参数
-
// 报错
-
function f3 (a1){
-
let a1;
-
}
-
// 不报错
-
function f4 (a2){
-
{
-
let a2
-
}
-
}
-
复制代码
1.1.2 const 命令
const
声明一个只读的常量。
基础用法:
-
const PI = 3.1415926;
-
console.log(PI); // 3.1415926
-
复制代码
注意点:
const
声明后,无法修改值;
-
const PI = 3.1415926;
-
PI = 3;
-
// TypeError: Assignment to constant variable.
-
复制代码
const
声明时,必须赋值;
-
const a ;
-
// SyntaxError: Missing initializer in const declaration.
-
复制代码
const
声明的常量,let
不能重复声明;
-
const PI = 3.1415926;
-
let PI = 0;
-
// Uncaught SyntaxError: Identifier 'PI' has already been declared
-
复制代码
1.2 变量的解构赋值
解构赋值概念:在ES6中,直接从数组和对象中取值,按照对应位置,赋值给变量的操作。
1.2.1 数组
基础用法:
-
// ES6 之前
-
let a = 1;
-
let b = 2;
-
// ES6 之后
-
let [a, b] = [1, 2];
-
复制代码
本质上,只要等号两边模式一致,左边变量即可获取右边对应位置的值,更多用法:
-
let [a, [[b], c]] = [1, [[2], 3]];
-
console.log(a, b, c); // 1, 2, 3
-
let [ , , c] = [1, 2, 3];
-
console.log(c); // 3
-
let [a, , c] = [1, 2, 3];
-
console.log(a,c); // 1, 3
-
let [a, ...b] = [1, 2, 3];
-
console.log(a,b); // 1, [2,3]
-
let [a, b, ..c.] = [1];
-
console.log(a, b, c); // 1, undefined, []
-
复制代码
注意点:
- 如果解构不成功,变量的值就等于
undefined
。
-
let [a] = []; // a => undefined
-
let [a, b] = [1]; // a => 1 , b => undefined
-
复制代码
- 当左边模式多于右边,也可以解构成功。
-
let [a, b] = [1, 2, 3];
-
console.log(a, b); // 1, 2
-
复制代码
- 两边模式不同,报错。
-
let [a] = 1;
-
let [a] = false;
-
let [a] = NaN;
-
let [a] = undefined;
-
let [a] = null;
-
let [a] = {};
-
复制代码
指定解构的默认值:
基础用法:
-
let [a = 1] = []; // a => 1
-
let [a, b = 2] = [a]; // a => 1 , b => 2
-
复制代码
特殊情况:
-
let [a = 1] = [undefined]; // a => 1
-
let [a = 1] = [null]; // a => null
-
复制代码
右边模式对应的值,必须严格等于undefined
,默认值才能生效,而null
不严格等于undefined
。
1.2.2 对象的解构赋值
与数组解构不同的是,对象解构不需要严格按照顺序取值,而只要按照变量名去取对应属性名的值,若取不到对应属性名的值,则为undefined
。
基础用法:
-
let {a, b} = {a:1, b:2}; // a => 1 , b => 2
-
let {a, b} = {a:2, b:1}; // a => 2 , b => 1
-
let {a} = {a:3, b:2, c:1};// a => 3
-
let {a} = {b:2, c:1}; // a => undefined
-
复制代码
注意点:
- 若变量名和属性名不一致,则需要修改名称。
-
let {a:b} = {a:1, c:2};
-
// error: a is not defined
-
// b => 1
-
复制代码
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
上面代码中,a
是匹配的模式,b
才是变量。真正被赋值的是变量b
,而不是模式a
。
- 对象解构也支持嵌套解构。
-
let obj = {
-
a:[ 1, { b: 2}]
-
};
-
let {a, a: [c, {b}]} = obj;
-
// a=>[1, {b: 2}], b => 2, c => 1
-
复制代码
指定解构的默认值:
-
let {a=1} = {}; // a => 1
-
let {a, b=1} = {a:2}; // a => 2, b => 1
-
let {a:b=3} = {}; // b => 3
-
let {a:b=3} = {a:4}; // b = >4
-
// a是模式,b是变量 牢记
-
let {a=1} = {a:undefined}; // a => 1
-
let {a=1} = {a:null}; // a => null
-
// 因为null与undefined不严格相等,所以赋值有效
-
// 导致默认值1不会生效。
-
复制代码
1.2.3 字符串的解构赋值
字符串的解构赋值中,字符串被转换成了一个类似数组的对象。 基础用法:
-
const [a, b, c, d, e] = 'hello';
-
a // "h"
-
b // "e"
-
c // "l"
-
d // "l"
-
e // "o"
-
let {length:len} = 'hello';// len => 5
-
复制代码
1.2.4 数值和布尔值的解构赋值
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined
和null
无法转为对象,所以对它们进行解构赋值,都会报错。
-
// 数值和布尔值的包装对象都有toString属性
-
let {toString: s} = 123;
-
s === Number.prototype.toString // true
-
let {toString: s} = true;
-
s === Boolean.prototype.toString // true
-
let { prop: x } = undefined; // TypeError
-
let { prop: y } = null; // TypeError
-
复制代码
1.2.5 函数参数的解构赋值
基础用法:
-
function fun ([a, b]){
-
return a + b;
-
}
-
fun ([1, 2]); // 3
-
复制代码
指定默认值的解构:
-
function fun ({a=0, b=0} = {}){
-
return [a, b];
-
}
-
fun ({a:1, b:2}); // [1, 2]
-
fun ({a:1}); // [1, 0]
-
fun ({}); // [0, 0]
-
fun (); // [0, 0]
-
function fun ({a, b} = {a:0, b:0}){
-
return [a, b];
-
}
-
fun ({a:1, b:2}); // [1, 2]
-
fun ({a:1}); // [1, undefined]
-
fun ({}); // [undefined, undefined]
-
fun (); // [0, 0]
-
复制代码
1.2.6 应用
- 交换变量的值:
-
let a = 1,b = 2;
-
[a, b] = [b, a]; // a =>2 , b => 1
-
复制代码
- 函数返回多个值:
-
// 返回一个数组
-
function f (){
-
return [1, 2, 3];
-
}
-
let [a, b, c] = f(); // a=>1, b=>2, c=>3
-
// 返回一个对象
-
function f (){
-
return {a:1, b:2};
-
}
-
let {a, b} = f(); // a=>1, b=>2
-
复制代码
- 快速对应参数: 快速的将一组参数与变量名对应。
-
function f([a, b, c]) {...}
-
f([1, 2, 3]);
-
function f({a, b, c}) {...}
-
f({b:2, c:3, a:1});
-
复制代码
- 提取JSON数据:
-
let json = {
-
name : 'leo',
-
age: 18
-
}
-
let {name, age} = json;
-
console.log(name,age); // leo, 18
-
复制代码
- 遍历Map结构:
-
const m = new Map();
-
m.set('a',1);
-
m.set('b',2);
-
for (let [k, v] of m){
-
console.log(k + ' : ' + v);
-
}
-
// 获取键名
-
for (let [k] of m){...}
-
// 获取键值
-
for (let [,k] of m){...}
-
复制代码
- 输入模块的指定方法: 用于按需加载模块中需要用到的方法。
-
const {log, sin, cos} = require('math');
-
复制代码
1.3 字符串的拓展
1.3.1 includes(),startsWith(),endsWith()
在我们判断字符串是否包含另一个字符串时,ES6之前,我们只有typeof
方法,ES6之后我们又多了三种方法:
- includes():返回布尔值,表示是否找到参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
-
let a = 'hello leo';
-
a.startsWith('leo'); // false
-
a.endsWith('o'); // true
-
a.includes('lo'); // true
-
复制代码
并且这三个方法都支持第二个参数,表示起始搜索的位置。
-
let a = 'hello leo';
-
a.startsWith('leo',1); // false
-
a.endsWith('o',5); // true
-
a.includes('lo',6); // false
-
复制代码
endsWith
是针对前 n
个字符,而其他两个是针对从第n
个位置直到结束。
1.3.2 repeat()
repeat
方法返回一个新字符串,表示将原字符串重复n
次。
基础用法:
-
'ab'.repeat(3); // 'ababab'
-
'ab'.repeat(0); // ''
-
复制代码
特殊用法:
- 参数为
小数
,则取整
-
'ab'.repeat(2.3); // 'abab'
-
复制代码
- 参数为
负数
或Infinity
,则报错
-
'ab'.repeat(-1); // RangeError
-
'ab'.repeat(Infinity); // RangeError
-
复制代码
- 参数为
0到-1的小数
或NaN
,则取0
-
'ab'.repeat(-0.5); // ''
-
'ab'.repeat(NaN); // ''
-
复制代码
- 参数为
字符串
,则转成数字
-
'ab'.repeat('ab'); // ''
-
'ab'.repeat('3'); // 'ababab'
-
复制代码
1.3.3 padStart(),padEnd()
用于将字符串头部或尾部补全长度,padStart()
为头部补全,padEnd()
为尾部补全。
这两个方法接收2个参数,第一个指定字符串最小长度,第二个用于补全的字符串。
基础用法 :
-
'x'.padStart(5, 'ab'); // 'ababx'
-
'x'.padEnd(5, 'ab'); // 'xabab'
-
复制代码
特殊用法:
- 原字符串长度,大于或等于指定最小长度,则返回原字符串。
-
'xyzabc'.padStart(5, 'ab'); // 'xyzabc'
-
复制代码
- 用来补全的字符串长度和原字符串长度之和,超过指定最小长度,则截去超出部分的补全字符串。
-
'ab'.padStart(5,'012345'); // "012ab"
-
复制代码
- 省略第二个参数,则用
空格
补全。
-
'x'.padStart(4); // ' x'
-
'x'.padEnd(4); // 'x '
-
复制代码
1.3.4 模版字符串
用于拼接字符串,ES6之前:
-
let a = 'abc' +
-
'def' +
-
'ghi';
-
复制代码
ES6之后:
-
let a = `
-
abc
-
def
-
ghi
-
`
-
复制代码
拼接变量: 在**反引号(`)**中使用${}
包裹变量或方法。
-
// ES6之前
-
let a = 'abc' + v1 + 'def';
-
// ES6之后
-
let a = `abc${v1}def`
-
复制代码
1.4 正则的拓展
1.4.1 介绍
在ES5中有两种情况。
- 参数是字符串,则第二个参数为正则表达式的修饰符。
-
let a = new RegExp('abc', 'i');
-
// 等价于
-
let a = /abx/i;
-
复制代码
- 参数是正则表达式,返回一个原表达式的拷贝,且不能有第二个参数,否则报错。
-
let a = new RegExp(/abc/i);
-
//等价于
-
let a = /abx/i;
-
let a = new RegExp(/abc/, 'i');
-
// Uncaught TypeError
-
复制代码
ES6中使用:
第一个参数是正则对象,第二个是指定修饰符,如果第一个参数已经有修饰符,则会被第二个参数覆盖。
-
new RegExp(/abc/ig, 'i');
-
复制代码
1.4.2 字符串的正则方法
常用的四种方法:match()
、replace()
、search()
和split()
。
1.4.3 u修饰符
添加u
修饰符,是为了处理大于uFFFF
的Unicode字符,即正确处理四个字节的UTF-16编码。
-
/^\uD83D/u.test('\uD83D\uDC2A'); // false
-
/^\uD83D/.test('\uD83D\uDC2A'); // true
-
复制代码
由于ES5之前不支持四个字节UTF-16编码,会识别为两个字符,导致第二行输出true
,加入u
修饰符后ES6就会识别为一个字符,所以输出false
。
注意:
加上u
修饰符后,会改变下面正则表达式的行为:
- (1)点字符 点字符(
.
)在正则中表示除了换行符以外的任意单个字符。对于码点大于0xFFFF
的Unicode字符,点字符不能识别,必须加上u
修饰符。
-
var a = "?";
-
/^.$/.test(a); // false
-
/^.$/u.test(a); // true
-
复制代码
- (2)Unicode字符表示法 使用ES6新增的大括号表示Unicode字符时,必须在表达式添加
u
修饰符,才能识别大括号。
-
/\u{61}/.test('a'); // false
-
/\u{61}/u.test('a'); // true
-
/\u{20BB7}/u.test('?'); // true
-
复制代码
- (3)量词 使用
u
修饰符后,所有量词都会正确识别码点大于0xFFFF
的 Unicode 字符。
-
/a{2}/.test('aa'); // true
-
/a{2}/u.test('aa'); // true
-
/?{2}/.test('??'); // false
-
/?{2}/u.test('??'); // true
-
复制代码
- (4)i修饰符 不加
u
修饰符,就无法识别非规范的K
字符。
-
/[a-z]/i.test('\u212A') // false
-
/[a-z]/iu.test('\u212A') // true
-
复制代码
检查是否设置u
修饰符: 使用unicode
属性。
-
const a = /hello/;
-
const b = /hello/u;
-
a.unicode // false
-
b.unicode // true
-
复制代码
1.4.4 y修饰符
y
修饰符与g
修饰符类似,也是全局匹配,后一次匹配都是从上一次匹配成功的下一个位置开始。区别在于,g
修饰符只要剩余位置中存在匹配即可,而y
修饰符是必须从剩余第一个开始。
-
var s = 'aaa_aa_a';
-
var r1 = /a+/g;
-
var r2 = /a+/y;
-
r1.exec(s) // ["aaa"]
-
r2.exec(s) // ["aaa"]
-
r1.exec(s) // ["aa"] 剩余 '_aa_a'
-
r2.exec(s) // null
-
复制代码
lastIndex
属性: 指定匹配的开始位置:
-
const a = /a/y;
-
a.lastIndex = 2; // 从2号位置开始匹配
-
a.exec('wahaha'); // null
-
a.lastIndex = 3; // 从3号位置开始匹配
-
let c = a.exec('wahaha');
-
c.index; // 3
-
a.lastIndex; // 4
-
复制代码
返回多个匹配:
一个y
修饰符对match
方法只能返回第一个匹配,与g
修饰符搭配能返回所有匹配。
-
'a1a2a3'.match(/a\d/y); // ["a1"]
-
'a1a2a3'.match(/a\d/gy); // ["a1", "a2", "a3"]
-
复制代码
检查是否使用y
修饰符:
使用sticky
属性检查。
-
const a = /hello\d/y;
-
a.sticky; // true
-
复制代码
1.4.5 flags属性
flags
属性返回所有正则表达式的修饰符。
-
/abc/ig.flags; // 'gi'
-
复制代码
1.5 数值的拓展
1.5.1 Number.isFinite(), Number.isNaN()
Number.isFinite()
用于检查一个数值是否是有限的,即不是Infinity
,若参数不是Number
类型,则一律返回false
。
-
Number.isFinite(10); // true
-
Number.isFinite(0.5); // true
-
Number.isFinite(NaN); // false
-
Number.isFinite(Infinity); // false
-
Number.isFinite(-Infinity); // false
-
Number.isFinite('leo'); // false
-
Number.isFinite('15'); // false
-
Number.isFinite(true); // false
-
Number.isFinite(Math.random()); // true
-
复制代码
Number.isNaN()
用于检查是否是NaN
,若参数不是NaN
,则一律返回false
。
-
Number.isNaN(NaN); // true
-
Number.isNaN(10); // false
-
Number.isNaN('10'); // false
-
Number.isNaN(true); // false
-
Number.isNaN(5/NaN); // true
-
Number.isNaN('true' / 0); // true
-
Number.isNaN('true' / 'true'); // true
-
复制代码
区别:
与传统全局的isFinite()
和isNaN()
方法的区别,传统的这两个方法,是先将参数转换成数值,再判断。
而ES6新增的这两个方法则只对数值有效, Number.isFinite()
对于非数值一律返回false
,Number.isNaN()
只有对于NaN
才返回true
,其他一律返回false
。
-
isFinite(25); // true
-
isFinite("25"); // true
-
Number.isFinite(25); // true
-
Number.isFinite("25"); // false
-
isNaN(NaN); // true
-
isNaN("NaN"); // true
-
Number.isNaN(NaN); // true
-
Number.isNaN("NaN"); // false
-
复制代码
1.5.2 Number.parseInt(), Number.parseFloat()
这两个方法与全局方法parseInt()
和parseFloat()
一致,目的是逐步减少全局性的方法,让语言更模块化。
-
parseInt('12.34'); // 12
-
parseFloat('123.45#'); // 123.45
-
Number.parseInt('12.34'); // 12
-
Number.parseFloat('123.45#'); // 123.45
-
Number.parseInt === parseInt; // true
-
Number.parseFloat === parseFloat; // true
-
复制代码
1.5.3 Number.isInteger()
用来判断一个数值是否是整数,若参数不是数值,则返回false
。
-
Number.isInteger(10); // true
-
Number.isInteger(10.0); // true
-
Number.isInteger(10.1); // false
-
复制代码
1.5.4 Math对象的拓展
ES6新增17个数学相关的静态方法,只能在Math对象上调用。
- Math.trunc:
用来去除小数的小数部分,返回整数部分。
若参数为非数值,则先转为数值。
若参数为空值或无法截取整数的值,则返回NaN。
-
// 正常使用
-
Math.trunc(1.1); // 1
-
Math.trunc(1.9); // 1
-
Math.trunc(-1.1); // -1
-
Math.trunc(-1.9); // -1
-
Math.trunc(-0.1234); // -0
-
// 参数为非数值
-
Math.trunc('11.22'); // 11
-
Math.trunc(true); // 1
-
Math.trunc(false); // 0
-
Math.trunc(null); // 0
-
// 参数为空和无法取整
-
Math.trunc(NaN); // NaN
-
Math.trunc('leo'); // NaN
-
Math.trunc(); // NaN
-
Math.trunc(undefined); // NaN
-
复制代码
ES5实现:
-
Math.trunc = Math.trunc || function(x){
-
return x < 0 ? Math.ceil(x) : Math.floor(x);
-
}
-
复制代码
- Math.sign():
判断一个数是正数、负数还是零,对于非数值,会先转成数值。
返回值:- 参数为正数, 返回 +1
- 参数为负数, 返回 -1
- 参数为0, 返回 0
- 参数为-0, 返回 -0
- 参数为其他值, 返回 NaN
-
Math.sign(-1); // -1
-
Math.sign(1); // +1
-
Math.sign(0); // 0
-
Math.sign(-0); // -0
-
Math.sign(NaN); // NaN
-
Math.sign(''); // 0
-
Math.sign(true); // +1
-
Math.sign(false);// 0
-
Math.sign(null); // 0
-
Math.sign('9'); // +1
-
Math.sign('leo');// NaN
-
Math.sign(); // NaN
-
Math.sign(undefined); // NaN
-
复制代码
ES5实现
-
Math.sign = Math.sign || function (x){
-
x = +x;
-
if (x === 0 || isNaN(x)){
-
return x;
-
}
-
return x > 0 ? 1: -1;
-
}
-
复制代码
- Math.cbrt():
用来计算一个数的立方根,若参数为非数值则先转成数值。
-
Math.cbrt(-1); // -1
-
Math.cbrt(0); // 0
-
Math.cbrt(1); // 1
-
Math.cbrt(2); // 1.2599210498
-
Math.cbrt('1'); // 1
-
Math.cbrt('leo'); // NaN
-
复制代码
ES5实现
-
Math.cbrt = Math.cbrt || function (x){
-
var a = Math.pow(Math.abs(x), 1/3);
-
return x < 0 ? -y : y;
-
}
-
复制代码
- Math.clz32():
用于返回一个数的 32 位无符号整数形式有多少个前导 0。
-
Math.clz32(0) // 32
-
Math.clz32(1) // 31
-
Math.clz32(1000) // 22
-
Math.clz32(0b01000000000000000000000000000000) // 1
-
Math.clz32(0b00100000000000000000000000000000) // 2
-
复制代码
- Math.imul():
用于返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。
-
Math.imul(2, 4) // 8
-
Math.imul(-1, 8) // -8
-
Math.imul(-2, -2) // 4
-
复制代码
- Math.fround():
用来返回一个数的2位单精度浮点数形式。
-
Math.fround(0) // 0
-
Math.fround(1) // 1
-
Math.fround(2 ** 24 - 1) // 16777215
-
复制代码
- Math.hypot():
用来返回所有参数的平方和的平方根。
-
Math.hypot(3, 4); // 5
-
Math.hypot(3, 4, 5); // 7.0710678118654755
-
Math.hypot(); // 0
-
Math.hypot(NaN); // NaN
-
Math.hypot(3, 4, 'foo'); // NaN
-
Math.hypot(3, 4, '5'); // 7.0710678118654755
-
Math.hypot(-3); // 3
-
复制代码
- Math.expm1():
用来返回ex - 1
,即Math.exp(x) - 1
。
-
Math.expm1(-1) // -0.6321205588285577
-
Math.expm1(0) // 0
-
Math.expm1(1) // 1.718281828459045
-
复制代码
ES5实现
-
Math.expm1 = Math.expm1 || function(x) {
-
return Math.exp(x) - 1;
-
};
-
复制代码
- Math.log1p():
用来返回1 + x
的自然对数,即Math.log(1 + x)
。如果x小于-1
,返回NaN
。
-
Math.log1p(1) // 0.6931471805599453
-
Math.log1p(0) // 0
-
Math.log1p(-1) // -Infinity
-
Math.log1p(-2) // NaN
-
复制代码
ES5实现
-
Math.log1p = Math.log1p || function(x) {
-
return Math.log(1 + x);
-
};
-
复制代码
- Math.log10():
用来返回以10
为底的x的对数
。如果x小于 0,则返回NaN
。
-
Math.log10(2) // 0.3010299956639812
-
Math.log10(1) // 0
-
Math.log10(0) // -Infinity
-
Math.log10(-2) // NaN
-
Math.log10(100000) // 5
-
复制代码
ES5实现
-
Math.log10 = Math.log10 || function(x) {
-
return Math.log(x) / Math.LN10;
-
};
-
复制代码
- Math.log2():
用来返回以2
为底的x的对数
。如果x
小于0
,则返回NaN
。
-
Math.log2(3) // 1.584962500721156
-
Math.log2(2) // 1
-
Math.log2(1) // 0
-
Math.log2(0) // -Infinity
-
Math.log2(-2) // NaN
-
Math.log2(1024) // 10
-
Math.log2(1 << 29) // 29
-
复制代码
ES5实现
-
Math.log2 = Math.log2 || function(x) {
-
return Math.log(x) / Math.LN2;
-
};
-
复制代码
- 双曲函数方法:
Math.sinh(x)
返回x的双曲正弦(hyperbolic sine)Math.cosh(x)
返回x的双曲余弦(hyperbolic cosine)Math.tanh(x)
返回x的双曲正切(hyperbolic tangent)Math.asinh(x)
返回x的反双曲正弦(inverse hyperbolic sine)Math.acosh(x)
返回x的反双曲余弦(inverse hyperbolic cosine)Math.atanh(x)
返回x的反双曲正切(inverse hyperbolic tangent)
1.5.5 指数运算符
新增的指数运算符(**
):
-
2 ** 2; // 4
-
2 ** 3; // 8
-
2 ** 3 ** 2; // 相当于 2 ** (3 ** 2); 返回 512
-
复制代码
指数运算符(**
)与Math.pow
的实现不相同,对于特别大的运算结果,两者会有细微的差异。
-
Math.pow(99, 99)
-
// 3.697296376497263e+197
-
99 ** 99
-
// 3.697296376497268e+197
-
复制代码
1.6 函数的拓展
1.6.1 参数默认值
-
// ES6 之前
-
function f(a, b){
-
b = b || 'leo';
-
console.log(a, b);
-
}
-
// ES6 之后
-
function f(a, b='leo'){
-
console.log(a, b);
-
}
-
f('hi'); // hi leo
-
f('hi', 'jack'); // hi jack
-
f('hi', ''); // hi leo
-
复制代码
注意:
- 参数变量是默认声明的,不能用
let
和const
再次声明:
-
function f (a = 1){
-
let a = 2; // error
-
}
-
复制代码
- 使用参数默认值时,参数名不能相同:
-
function f (a, a, b){ ... }; // 不报错
-
function f (a, a, b = 1){ ... }; // 报错
-
复制代码
与解构赋值默认值结合使用:
-
function f ({a, b=1}){
-
console.log(a,b)
-
};
-
f({}); // undefined 1
-
f({a:2}); // 2 1
-
f({a:2, b:3}); // 2 3
-
f(); // 报错
-
function f ({a, b = 1} = {}){
-
console.log(a, b)
-
}
-
f(); // undefined 1
-
复制代码
尾参数定义默认值:
通常在尾参数定义默认值,便于观察参数,并且非尾参数无法省略。
-
function f (a=1,b){
-
return [a, b];
-
}
-
f(); // [1, undefined]
-
f(2); // [2, undefined]
-
f(,2); // 报错
-
f(undefined, 2); // [1, 2]
-
function f (a, b=1, c){
-
return [a, b, c];
-
}
-
f(); // [undefined, 1, undefined]
-
f(1); // [1,1,undefined]
-
f(1, ,2); // 报错
-
f(1,undefined,2); // [1,1,2]
-
复制代码
在给参数传递默认值时,传入undefined
会触发默认值,传入null
不会触发。
-
function f (a = 1, b = 2){
-
console.log(a, b);
-
}
-
f(undefined, null); // 1 null
-
复制代码
函数的length属性:length
属性将返回,没有指定默认值的参数数量,并且rest参数不计入length
属性。
-
function f1 (a){...};
-
function f2 (a=1){...};
-
function f3 (a, b=2){...};
-
function f4 (...a){...};
-
function f5 (a,b,...c){...};
-
f1.length; // 1
-
f2.length; // 0
-
f3.length; // 1
-
f4.length; // 0
-
f5.length; // 2
-
复制代码
1.6.2 rest 参数
rest
参数形式为(...变量名
),其值为一个数组,用于获取函数多余参数。
-
function f (a, ...b){
-
console.log(a, b);
-
}
-
f(1,2,3,4); // 1 [2, 3, 4]
-
复制代码
注意:
rest
参数只能放在最后一个,否则报错:
-
function f(a, ...b, c){...}; // 报错
-
复制代码
- 函数的
length
属性不包含rest
参数。
-
function f1 (a){...};
-
function f2 (a,...b){...};
-
f1(1); // 1
-
f2(1,2); // 1
-
复制代码
1.6.3 name 属性
用于返回该函数的函数名。
-
function f (){...};
-
f.name; // f
-
const f = function g(){...};
-
f.name; // g
<