参考书籍
ES6简介
- 与javascript关系
- 是javascript的规格
 - javascirpt是其实现
 
 - 与ES2015关系
- ES6是一个泛指,指5.1版本后的下一代标准,含ES2015 ES2016 ES2017等
 
 - Babel转码器
- ES6代码转ES5
 
 
let与const
let
- let声明的变量只在let所在的代码块有效
 for循环中和适合用let
for (let i = 0; i < 3; i++) {let i = 'abc';console.log(i);}// abc// abc// abc//这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。
不存在变量提升 ```javascript // var 的情况 console.log(foo); // 输出undefined var foo = 2;
// let 的情况 console.log(bar); // 报错ReferenceError let bar = 2;
- 暂时性死区```javascriptvar tmp = 123;if (true) {tmp = 'abc'; // ReferenceErrorlet tmp;}//隐蔽的死区 是因为参数x默认值等于另一个参数y,而此时y还没有声明,属于“死区”。function bar(x = y, y = 2) {return [x, y];}bar(); // 报错
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“**暂时性死 区**”(temporal dead zone,简称 TDZ)
function f() { console.log(tmp); if (false) { var tmp = ‘hello world’; } }
f(); // undefined 变量提升,导致内层的tmp变量覆盖了外层的tmp变量。
var s = ‘hello’;
for (var i = 0; i < s.length; i++) { console.log(s[i]); }
console.log(i); // 5 循环结束后,它并没有消失,泄露成了全局变量。
- ES6 的块级作用域- 块级作用域与函数声明 //实现和语法规定有些不一样<a name="SnFIC"></a>### Const命令- 声明一个只读的常量。一旦声明,常量的值就不能改变。- const的作用域与let命令相同:只在声明所在的块级作用域内有效。- 本质- 地址不变,所以在将一个对象声明为常量必须非常小心。如果真的想将对象冻结,应该使用Object.freeze方法。- ES6 声明变量的六种方法- var function let const import class<a name="yKDxh"></a>### 顶层对象属性- 在es5中 ,浏览器中顶层对象是windows 所以 a=1 与 windows.a=1 等价- es6中将 顶层对象与全局变量脱钩,为保持兼容性, var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性<a name="L1mLO"></a>### globalThis 对象- 顶层对象在各种实现里面是不统一的。- 勉强可以在任意实现环境下拿到顶层对象的代码如下```javascript// 方法一(typeof window !== 'undefined'? window: (typeof process === 'object' &&typeof require === 'function' &&typeof global === 'object')? global: this);// 方法二var getGlobal = function () {if (typeof self !== 'undefined') { return self; }if (typeof window !== 'undefined') { return window; }if (typeof global !== 'undefined') { return global; }throw new Error('unable to locate global object');};
ES2020 引入globalThis 拿取顶层对象
变量的解构赋值
数组的解构赋值
基本用法
- 只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。 ```javascript let [a, b, c] = [1, 2, 3]; let [foo, [[bar], baz]] = [1, [[2], 3]]; foo // 1 bar // 2 baz // 3 let [ , , third] = [“foo”, “bar”, “baz”]; third // “baz”
 
let [x, , y] = [1, 2, 3]; x // 1 y // 3
let [head, …tail] = [1, 2, 3, 4]; head // 1 tail // [2, 3, 4]
let [x, y, …z] = [‘a’]; x // “a” y // undefined //结构不成功 变量的值就等于undefined z // []
- 默认值```javascriptlet [foo = true] = [];foo // truelet [x, y = 'b'] = ['a']; // x='a', y='b'let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
对象的解构赋值
- 简介 ```javascript let { foo, bar } = { foo: ‘aaa’, bar: ‘bbb’ }; foo // “aaa” bar // “bbb” let {foo} = {bar: ‘baz’}; foo // undefined
 
// 例一 let { log, sin, cos } = Math; //将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多
// 例二 const { log } = console; log(‘hello’) // hello
let obj = { first: ‘hello’, last: ‘world’ }; let { first: f, last: l } = obj; f // ‘hello’ l // ‘world’
//嵌套的情况
let obj = { p: [ ‘Hello’, { y: ‘World’ } ] };
let { p: [x, { y }] } = obj; x // “Hello” y // “World”
const node = { loc: { start: { line: 1, column: 5 } } };
let { loc, loc: { start }, loc: { start: { line }} } = node; line // 1 loc // Object {start: Object} start // Object {line: 1, column: 5}
//有三次解构赋值
//可以取到继承的属性 const obj1 = {}; const obj2 = { foo: ‘bar’ }; Object.setPrototypeOf(obj1, obj2);
const { foo } = obj1; foo // “bar”
- 默认值```javascriptvar {x = 3} = {};x // 3var {x, y = 5} = {x: 1};x // 1y // 5var {x: y = 3} = {};y // 3var {x: y = 3} = {x: 5};y // 5var { message: msg = 'Something went wrong' } = {};msg // "Something went wrong"var {x = 3} = {x: undefined};x // 3var {x = 3} = {x: null};x // null
- 注意点
let arr = [1, 2, 3];let {0 : first, [arr.length - 1] : last} = arr;first // 1last // 3
字符串的解构赋值
```javascript //字符串会被转换成类似数组的类型, 有属性length const [a, b, c, d, e] = ‘hello’; a // “h” b // “e” c // “l” d // “l” e // “o” 
let {length : len} = ‘hello’; len // 5
<a name="fBREj"></a>### 数值和布尔值的解构赋值```javascript//数值和布尔值的包装对象都有toString属性,因此变量s都能取到值。let {toString: s} = 123;s === Number.prototype.toString // truelet {toString: s} = true;s === Boolean.prototype.toString // true解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
圆括号问题
- 不能使用的情况 ```javascript // 全部报错 因为它们都是变量声明语句,模式不能使用圆括号。 let [(a)] = [1];
 
let {x: (c)} = {}; let ({x: c}) = {}; let {(x: c)} = {}; let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
// 报错 函数参数也属于变量声明,因此不能带有圆括号。 function f([(z)]) { return z; } // 报错 function f([z,(x)]) { return x; }
// 全部报错 赋值语句的模式 ({ p: a }) = { p: 42 }; ([a]) = [5];
- 能使用的情况- 可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。```javascript[(b)] = [3]; // 正确({ p: (d) } = {}); // 正确[(parseInt.prop)] = [3]; // 正确
用途
- 交换变量
 - 从函数返回多个值
 - 函数参数的定义
 - 提取 JSON 数据 ```javascript let jsonData = { id: 42, status: “OK”, data: [867, 5309] };
 
let { id, status, data: number } = jsonData;
console.log(id, status, number); // 42, “OK”, [867, 5309]
- 函数参数的默认值```javascriptjQuery.ajax = function (url, {async = true,beforeSend = function () {},cache = true,complete = function () {},crossDomain = false,global = true,// ... more config} = {}) {// ... do stuff};
- 遍历 Map 结构 ```javascript for (let [key, value] of map) { console.log(key + “ is “ + value); } // first is hello // second is world // 获取键名 for (let [key] of map) { // … }
 
// 获取键值 for (let [,value] of map) { // … }
- 输入模块的指定方法```javascriptconst { SourceMapConsumer, SourceNode } = require("source-map");
字符串扩展
字符的unicode表示方法
//6种表示字符方法'\z' === 'z' // true'\172' === 'z' // true'\x7A' === 'z' // true'\u007A' === 'z' // true 这种表示法只限于码点在\u0000~\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。'\u{7A}' === 'z' // true//如果直接在\u后面跟上超过0xFFFF的数值(比如\u20BB7),JavaScript 会理解成\u20BB+7。由于\u20BB是一个不可打印字符,所以只会显示一个空格,后面跟着一个7。
字符串的遍历器接口
- es6为字符串添加了遍历接口
 - 这个遍历器最大的优点是可以识别大于0xFFFF的码点,传统的for循环无法识别这样的码点。 ```javascript for (let codePoint of ‘foo’) { console.log(codePoint) } // “f” // “o” // “o”
 
let text = String.fromCodePoint(0x20BB7);
for (let i = 0; i < text.length; i++) { console.log(text[i]); } // “ “ // “ “
for (let i of text) { console.log(i); } // “𠮷”
<a name="WPxY4"></a>### 直接输入 U+2028 和 U+2029- JavaScript 字符串允许直接输入字符,以及输入字符的转义形式```javascript'中' === '\u4e2d' // true
JavaScript 规定有5个字符,不能在字符串里面直接使用,只能使用转义形式。
\uD834\uDF06是两个码点,但是必须放在一起配对使用,代表字符𝌆
ES2019 改变了JSON.stringify()的行为。如果遇到0xD800到0xDFFF之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。
模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
- 如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中
 - 模板字符串中嵌入变量,需要将变量名写在${}之中。
 - 大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。
 - 模板字符串之中还能调用函数。 ```javascript //传统 (‘#result’).append( ‘There are ‘ + basket.count + ‘ ‘ + ‘items in your basket, ‘ + ‘‘ + basket.onSale + ‘ are on sale!’ );
 
//ES6
$(‘#result’).append(There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!);
// 普通字符串
In JavaScript '\n' is a line-feed.
// 多行字符串
In JavaScript this is
 not legal.
console.log(string text line 1
string text line 2);
// 字符串中嵌入变量
let name = “Bob”, time = “today”;
Hello ${name}, how are you ${time}?
function fn() { return “Hello World”; }
foo ${fn()} bar
// foo Hello World bar
- 模板字符串甚至还能嵌套。```javascriptconst tmpl = addrs => `<table>${addrs.map(addr => `<tr><td>${addr.first}</td></tr><tr><td>${addr.last}</td></tr>`).join('')}</table>`;const data = [{ first: '<Jane>', last: 'Bond' },{ first: 'Lars', last: '<Croft>' },];console.log(tmpl(data));// <table>//// <tr><td><Jane></td></tr>// <tr><td>Bond</td></tr>//// <tr><td>Lars</td></tr>// <tr><td><Croft></td></tr>//// </table>let func = (name) => `Hello ${name}!`;func('Jack') // "Hello Jack!"
模板编译
let template = `<ul><% for(let i=0; i < data.supplies.length; i++) { %><li><%= data.supplies[i] %></li><% } %></ul>`;function compile(template){const evalExpr = /<%=(.+?)%>/g;const expr = /<%([\s\S]+?)%>/g;template = template.replace(evalExpr, '`); \n echo( $1 ); \n echo(`').replace(expr, '`); \n $1 \n echo(`');template = 'echo(`' + template + '`);';let script =`(function parse(data){let output = "";function echo(html){output += html;}${ template }return output;})`;return script;}let parse = eval(compile(template));div.innerHTML = parse({ supplies: [ "broom", "mop", "cleaner" ] });// <ul>// <li>broom</li>// <li>mop</li>// <li>cleaner</li>// </ul>
标签模板
- “标签模板”的一个重要应用,就是过滤 HTML 字符串,防止用户输入恶意内容。 ```javascript let a = 5; let b = 10;
 
function tag(s, v1, v2) { console.log(s[0]); console.log(s[1]); console.log(s[2]); console.log(v1); console.log(v2);
return “OK”; }
tagHello ${ a + b } world ${ a * b};
// “Hello “
// “ world “
// “”
// 15
// 50
// “OK”
<a name="v3aOK"></a>### 模板字符串的限制<br />- ES2018 [放松](https://tc39.github.io/proposal-template-literal-revision/)了对标签模板里面的字符串转义的限制。如果遇到不合法的字符串转义,就返回undefined,而不是报错,并且从raw属性上面可以得到原始字符串。<a name="CyiZo"></a>## 字符串新增方法<a name="q3tev"></a>### String.fromCodePoint- String.fromCharCode()不能识别大于0xFFFF的码点,所以0x20BB7就发生了溢出,最高位2被舍弃了- ES6 提供了String.fromCodePoint()方法,可以识别大于0xFFFF的字符<a name="wB6ff"></a>### String.raw```javascriptString.raw`Hi\n${2+3}!`// 实际返回 "Hi\\n5!",显示的是转义后的结果 "Hi\n5!"String.raw`Hi\\n`// 返回 "Hi\\\\n"String.raw`Hi\\n` === "Hi\\\\n" // true// `foo${1 + 2}bar`// 等同于String.raw({ raw: ['foo', 'bar'] }, 1 + 2) // "foo3bar"
codePointAt
- codePointAt()方法会正确返回 32 位的 UTF-16 字符的码点。对于那些两个字节储存的常规字符,它的返回结果与charCodeAt()方法相同。 ```javascript et s = ‘𠮷a’;
 
s.codePointAt(0).toString(16) // “20bb7” s.codePointAt(2).toString(16) // “61”
//字符a在字符串s的正确位置序号应该是 1,但是必须向codePointAt()方法传入 2。 解决这个问题的一个办法是使用for…of循环,因为它会正确识别 32 位的 UTF-16 字符。 let s = ‘𠮷a’; for (let ch of s) { console.log(ch.codePointAt(0).toString(16)); } // 20bb7 // 61
codePointAt()方法是测试一个字符由两个字节还是由四个字节组成的最简单方法。 function is32Bit(c) { return c.codePointAt(0) > 0xFFFF; }
is32Bit(“𠮷”) // true is32Bit(“a”) // false
<a name="ozyXQ"></a>### 实例方法:normalize()```javascript// O(\u004F)和ˇ(\u030C)合成Ǒ(\u004F\u030C)但js不支持'\u01D1'==='\u004F\u030C' //false'\u01D1'.length // 1'\u004F\u030C'.length // 2ES6 提供字符串实例的normalize()方法,用来将字符的不同表示方法统一为同样的形式,这称为 Unicode 正规化。'\u01D1'.normalize() === '\u004F\u030C'.normalize()// true//有不同标准的'\u004F\u030C'.normalize('NFC').length // 1'\u004F\u030C'.normalize('NFD').length // 2
includes, startsWith,endsWith
let s = 'Hello world!';s.startsWith('world', 6) // trues.endsWith('Hello', 5) // trues.includes('Hello', 6) // false
repeat
padsStart padsEnd
trimStart trimEnd
matchAll
replaceAll
正则扩展
RegExp 构造函数
var regex = new RegExp('xyz', 'i');// 等价于var regex = /xyz/i;var regex = new RegExp(/xyz/i);// 等价于var regex = /xyz/i;
字符串的正则方法
String.prototype.match 调用 RegExp.prototype[Symbol.match]String.prototype.replace 调用 RegExp.prototype[Symbol.replace]String.prototype.search 调用 RegExp.prototype[Symbol.search]String.prototype.split 调用 RegExp.prototype[Symbol.split]
u修饰符
/^\uD83D/u.test('\uD83D\uDC2A') // false/^\uD83D/.test('\uD83D\uDC2A') // true
- 点字符 ```javascript var s = ‘𠮷’;
 
/^.$/.test(s) // false /^.$/u.test(s) // true
- **Unicode 字符表示法**```javascript/\u{61}/.test('a') // false/\u{61}/u.test('a') // true/\u{20BB7}/u.test('𠮷') // true
量词
/a{2}/.test('aa') // true/a{2}/u.test('aa') // true/𠮷{2}/.test('𠮷𠮷') // false/𠮷{2}/u.test('𠮷𠮷') // true
预定义模式 ```javascript /^\S$/.test(‘𠮷’) // false /^\S$/u.test(‘𠮷’) // true // \S是预定义模式,匹配所有非空白字符
function codePointLength(text) { var result = text.match(/[\s\S]/gu); return result ? result.length : 0; }
var s = ‘𠮷𠮷’;
s.length // 4 codePointLength(s) // 2
- **i 修饰符**```javascript/[a-z]/i.test('\u212A') // false/[a-z]/iu.test('\u212A') // true
- 转义
 
RegExp.prototype.unicode 属性
//正则实例对象新增unicode属性,表示是否设置了u修饰符。const r1 = /hello/;const r2 = /hello/u;r1.unicode // falser2.unicode // true
y修饰符
- 粘连修饰符 ```javascript 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”] r2.exec(s) // null //第一次执行的时候,两者行为相同,剩余字符串都是_aa_a。由于g修饰没有位置要求, //所以第二次执行会返回结果,而y修饰符要求匹配必须从头部开始,所以返回null。
<a name="CntJ7"></a>### RegExp.prototype.sticky 属性```javascript//ES6 的正则实例对象多了sticky属性,表示是否设置了y修饰符。var r = /hello\d/y;r.sticky // true
RegExp.prototype.flags 属性
// ES5 的 source 属性// 返回正则表达式的正文/abc/ig.source// "abc"// ES6 的 flags 属性// 返回正则表达式的修饰符/abc/ig.flags// 'gi'
s 修饰符:dotAll 模式
// . 除了个字节的 UTF-16 字符和终止符都可以表示//ES2018 引入s修饰符,使得.可以匹配任意单个字符。const re = /foo.bar/s;// 另一种写法// const re = new RegExp('foo.bar', 's');re.test('foo\nbar') // truere.dotAll // truere.flags // 's'
后行断言
Unicode 属性类
ES2018 引入了一种新的类的写法\p{...}和\P{...},允许正则表达式匹配符合 Unicode 某种属性的所有字符。const regexGreekSymbol = /\p{Script=Greek}/u;regexGreekSymbol.test('π') // true// 匹配所有空格\p{White_Space}// 匹配各种文字的所有字母,等同于 Unicode 版的 \w[\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]// 匹配各种文字的所有非字母的字符,等同于 Unicode 版的 \W[^\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]// 匹配 Emoji/\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu// 匹配所有的箭头字符const regexArrows = /^\p{Block=Arrows}+$/u;regexArrows.test('←↑→↓↔↕↖↗↘↙⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇧⇩') // true
具名组匹配
- 正则表达式使用圆括号进行组匹配。 ```javascript const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
 
const matchObj = RE_DATE.exec(‘1999-12-31’); const year = matchObj[1]; // 1999 const month = matchObj[2]; // 12 const day = matchObj[3]; // 31
<a name="xU6iJ"></a>### 解构赋值和替换```javascriptlet {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar');one // footwo // barlet re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;'2015-01-02'.replace(re, '$<day>/$<month>/$<year>')// '02/01/2015''2015-01-02'.replace(re, (matched, // 整个匹配结果 2015-01-02capture1, // 第一个组匹配 2015capture2, // 第二个组匹配 01capture3, // 第三个组匹配 02position, // 匹配开始的位置 0S, // 原字符串 2015-01-02groups // 具名组构成的一个对象 {year, month, day}) => {let {day, month, year} = groups;return `${day}/${month}/${year}`;});
引用
- 如果要在正则表达式内部引用某个“具名组匹配”,可以使用\k<组名>的写法。
```javascript
const RE_TWICE = /^(?
[a-z]+)!\k $/; RE_TWICE.test(‘abc!abc’) // true RE_TWICE.test(‘abc!ab’) // false  
const RE_TWICE = /^(?
<a name="fm02T"></a>### 正则匹配索引```javascriptconst text = 'zabbcdef';const re = /ab/;const result = re.exec(text);result.index // 1result.indices // [ [1, 3] ]const re = /ab+(cd)/;const result = re.exec(text);result.indices // [ [ 1, 6 ], [ 4, 6 ] ]
String.prototype.matchAll()
///ES 2020 提供了这个方法const string = 'test1test2test3';const regex = /t(e)(st(\d?))/g;for (const match of string.matchAll(regex)) {console.log(match);}// ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"]// ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"]// ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]
数值扩展
二进制和八进制表示法
- ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。 ```javascript 0b111110111 === 503 // true 0o767 === 503 // true
 
// 非严格模式 (function(){ console.log(0o11 === 011); })() // true
// 严格模式 (function(){ ‘use strict’; console.log(0o11 === 011); })() // Uncaught SyntaxError: Octal literals are not allowed in strict
//如果要将0b和0o前缀的字符串数值转为十进制,要使用Number方法。
Number(‘0b111’) // 7 Number(‘0o10’) // 8
<a name="kPOY2"></a>### 数值分隔符- 欧美语言中,较长的数值允许每三位添加一个分隔符(通常是一个逗号),增加数值的可读性。比如,1000可以写作1,000- [ES2021](https://github.com/tc39/proposal-numeric-separator),允许 JavaScript 的数值使用下划线(_)作为分隔符。- 下面三个将字符串转成数值的函数,不支持数值分隔符。- Number()- parseInt()- parseFloat()<a name="EY19p"></a>### Number.isFinite(), Number.isNaN()```javascriptisFinite(25) // trueisFinite("25") // trueNumber.isFinite(25) // trueNumber.isFinite("25") // falseisNaN(NaN) // trueisNaN("NaN") // trueNumber.isNaN(NaN) // trueNumber.isNaN("NaN") // falseNumber.isNaN(1) // false
Number.parseInt(), Number.parseFloat()
// ES5的写法parseInt('12.34') // 12parseFloat('123.45#') // 123.45// ES6的写法Number.parseInt('12.34') // 12Number.parseFloat('123.45#') // 123.45
Number.isInteger()
//精度有限Number.isInteger(3.0000000000000002) // trueNumber.isInteger(5E-324) // falseNumber.isInteger(5E-325) // true
Number.EPSILON
- Number.EPSILON实际上是 JavaScript 能够表示的最小精度。误差如果小于这个值,就可以认为已经没有意义了,即不存在误差了。 ```javascript Number.EPSILON === Math.pow(2, -52) // true Number.EPSILON // 2.220446049250313e-16 Number.EPSILON.toFixed(20) // “0.00000000000000022204”
 
//Number.EPSILON可以用来设置“能够接受的误差范围”。比如,误差范围设为 2 的-50 次方(即Number.EPSILON * Math.pow(2, 2))
function withinErrorMargin (left, right) { return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2); }
0.1 + 0.2 === 0.3 // false withinErrorMargin(0.1 + 0.2, 0.3) // true
1.1 + 1.3 === 2.4 // false withinErrorMargin(1.1 + 1.3, 2.4) // true
<a name="Mq61p"></a>### 安全整数和 Number.isSafeInteger()- JavaScript 能够准确表示的整数范围在-2^53到2^53之间- ES6 引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,```javascriptNumber.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1// trueNumber.MAX_SAFE_INTEGER === 9007199254740991// trueNumber.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER// trueNumber.MIN_SAFE_INTEGER === -9007199254740991// true
Math 对象的扩展
- Math.trunc()
- 去除小数部分
 
 - Math.sign()
- 参数为正数,返回+1;
 - 参数为负数,返回-1;
 - 参数为 0,返回0;
 - 参数为-0,返回-0;
 - 其他值,返回NaN。
 
 - Math.cbrt()
- 立方根
 
 - Math.clz32() 
- Math.clz32()方法将参数转为 32 位无符号整数的形式,然后返回这个 32 位值里面有多少个前导 0。
 
 - Math.imul()
 - Math.fround()
- Math.fround方法返回一个数的32位单精度浮点数形式。
 
 - //
 
函数的扩展
函数参数的默认值
- 基本用法 ```javascript function Point(x = 0, y = 0) { this.x = x; this.y = y; }
 
const p = new Point(); p // { x: 0, y: 0 }
let x = 99; function foo(p = x + 1) { console.log(p); }
foo() // 100
x = 100; foo() // 101
- 与解构赋值默认值结合使用```javascriptfunction foo({x, y = 5}) {console.log(x, y);}foo({}) // undefined 5foo({x: 1}) // 1 5foo({x: 1, y: 2}) // 1 2foo() // TypeError: Cannot read property 'x' of undefinedfunction fetch(url, { body = '', method = 'GET', headers = {} }) {console.log(method);}fetch('http://example.com', {})// "GET"fetch('http://example.com')// 报错function fetch(url, { body = '', method = 'GET', headers = {} } = {}) {console.log(method);}fetch('http://example.com')// "GET"
- 参数默认值的位置 ```javascript / 例一 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]
- 函数的 length 属性```javascript//length属性的返回值,等于函数的参数个数减去指定了默认值的参数个数。(function (a) {}).length // 1(function (a = 5) {}).length // 0(function (a, b, c = 5) {}).length // 2
- 作用域 
- 一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。 ```javascript var x = 1;
 
 
function f(x, y = x) { console.log(y); }
f(2) // 2
//////// let x = 1;
function f(y = x) { let x = 2; console.log(y); }
f() // 1 ////////////////// var x = 1;
function foo(x = x) { // … }
foo() // ReferenceError: x is not defined
////////////// function f(y = x) { let x = 2; console.log(y); }
f() // ReferenceError: x is not defined
- 应用```javascriptfunction throwIfMissing() {throw new Error('Missing parameter');}function foo(mustBeProvided = throwIfMissing()) {return mustBeProvided;}foo()// Error: Missing parameter//表明这个参数可以省略function foo(optional = undefined) { ··· }
rest 参数
- 注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
 函数的length属性,不包括 rest 参数。 ```java function add(…values) { let sum = 0;
for (var val of values) { sum += val; }
return sum; }
add(2, 5, 3) // 10
// arguments变量的写法 function sortNumbers() { return Array.from(arguments).sort();//arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.from先将其转为数组。rest 参数就不存在这个问题, }
// rest参数的写法 const sortNumbers = (…numbers) => numbers.sort();
<a name="jP0nw"></a>### 严格模式```javafunction doSomething(a, b) {'use strict';// code}//------------'use strict';function doSomething(a, b = a) {// code}//------------const doSomething = (function () {'use strict';return function(value = 42) {return value;};}());
name 属性
var f = function () {};// ES5f.name // ""// ES6f.name // "f"const bar = function baz() {};// ES5bar.name // "baz"// ES6bar.name // "baz"(new Function).name // "anonymous"
箭头函数
var f = () => 5;// 等同于var f = function () { return 5 };var sum = (num1, num2) => num1 + num2;// 等同于var sum = function(num1, num2) {return num1 + num2;};
- 由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。 ```java // 报错 let getTempItem = id => { id: id, name: “Temp” };
 
// 不报错 let getTempItem = id => ({ id: id, name: “Temp” });
- 箭头函数可以与变量解构结合使用。```javaconst full = ({ first, last }) => first + ' ' + last;// 等同于function full(person) {return person.first + ' ' + person.last;}
- 箭头函数的一个用处是简化回调函数。 ```java // 普通函数写法 var result = values.sort(function (a, b) { return a - b; });
 
// 箭头函数写法 var result = values.sort((a, b) => a - b); ```
