函数式编程
函数式编程JavaScript 语言从一诞生,就具有函数式编程的烙印。它将函数作为一种独立的数据类型,与其他数据类型处于完全平等的地位。在 JavaScript 语言中,你可以采用面向对象编程,也可以采用函数式编程。有人甚至说,JavaScript 是有史以来第一种被大规模采用的函数式编程语言。
ES6 的种种新增功能,使得函数式编程变得更方便、更强大。本章介绍 ES6 如何进行函数式编程。
柯里化柯里化(currying)指的是将一个多参数的函数拆分成一系列函数,每个拆分后的函数都只接受一个参数(unary)。
12345function add(a, b) { return a + b;}add(1, 1); // 2
上面代码中,函数add接受两个参数a和b。
柯里化就是将上面的函数拆分成两个函数,每个函数都只接受一个参数。
12345678910function add(a) { return function(b) { return a + b; };}// 或者采用箭头函数写法const add = ...
函数的扩展
函数的扩展函数参数的默认值基本用法ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
12345678function log(x, y) { y = y || "World"; console.log(x, y);}log("Hello"); // Hello Worldlog("Hello", "China"); // Hello Chinalog("Hello", ""); // Hello World
上面代码检查函数log的参数y有没有赋值,如果没有,则指定默认值为World。这种写法的缺点在于,如果参数y赋值了,但是对应的布尔值为false,则该赋值不起作用。就像上面代码的最后一行,参数y等于空字符,结果被改为默认值。
为了避免这个问题,通常需要先判断一下参数y是否被赋值,如果没有,再等于默认值。
123if (typeof y === "undefined") { y = &quo ...
参考链接
参考链接官方文件
ECMAScript® 2015 Language Specification: ECMAScript 2015 规格
ECMAScript® 2016 Language Specification: ECMAScript 2016 规格
ECMAScript® 2017 Language Specification:ECMAScript 2017 规格(草案)
ECMAScript Current Proposals: ECMAScript 当前的所有提案
ECMAScript Active Proposals: 已经进入正式流程的提案
ECMAscript proposals:从阶段 0 到阶段 4 的所有提案列表
TC39 meeting agendas: TC39 委员会历年的会议记录
ECMAScript Daily: TC39 委员会的动态
The TC39 Process: 提案进入正式规格的流程
TC39: A Process Sketch, Stages 0 and 1: Stage 0 和 Stage 1 的含义
TC39 Process Sket ...
变量的解构赋值
变量的解构赋值数组的解构赋值基本用法ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
以前,为变量赋值,只能直接指定值。
123let a = 1;let b = 2;let c = 3;
ES6 允许写成下面这样。
1let [a, b, c] = [1, 2, 3];
上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。
1234567891011121314151617181920let [foo, [[bar], baz]] = [1, [[2], 3]];foo; // 1bar; // 2baz; // 3let [, , third] = ["foo", "bar", "baz"];third; // "baz"let [x, , y] = [1, 2, 3];x; // 1y; // 3let ...
字符串的扩展
字符串的扩展ES6 加强了对 Unicode 的支持,并且扩展了字符串对象。
字符的 Unicode 表示法JavaScript 允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点。
12"\u0061";// "a"
但是,这种表示法只限于码点在\u0000~`\uFFFF`之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。
12345"\uD842\uDFB7";// "𠮷""\u20BB7";// " 7"
上面代码表示,如果直接在\u后面跟上超过0xFFFF的数值(比如\u20BB7),JavaScript 会理解成\u20BB+7。由于\u20BB是一个不可打印字符,所以只会显示一个空格,后面跟着一个7。
ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。
1234567891011"\u{20BB7}";// "𠮷&quo ...
对象的扩展
对象的扩展属性的简洁表示法ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
123456const foo = "bar";const baz = { foo };baz; // {foo: "bar"}// 等同于const baz = { foo: foo };
上面代码表明,ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值。下面是另一个例子。
1234567891011function f(x, y) { return { x, y };}// 等同于function f(x, y) { return { x: x, y: y };}f(1, 2); // Object {x: 1, y: 2}
除了属性简写,方法也可以简写。
12345678910111213const o = { method() ...
数值的扩展
数值的扩展二进制和八进制表示法ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。
120b111110111 === 503; // true0o767 === 503; // true
从 ES5 开始,在严格模式之中,八进制就不再允许使用前缀0表示,ES6 进一步明确,要使用前缀0o表示。
123456789101112// 非严格模式(function() { console.log(0o11 === 011);})()( // true // 严格模式 function() { "use strict"; console.log(0o11 === 011); })(); // Uncaught SyntaxError: Octal literals are not allowed in strict mode.
如果要将0b和0o前缀的字符串数值转为十进制,要使用Number方法。
12Number("0b111"); // 7Num ...
数组的扩展
数组的扩展扩展运算符含义扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
12345678console.log(...[1, 2, 3])// 1 2 3console.log(1, ...[2, 3, 4], 5)// 1 2 3 4 5[...document.querySelectorAll('div')]// [<div>, <div>, <div>]
该运算符主要用于函数调用。
12345678910function push(array, ...items) { array.push(...items);}function add(x, y) { return x + y;}const numbers = [4, 38];add(...numbers); // 42
上面代码中,array.push(...items)和add(...numbers)这两行,都是函数的调用,它们的都使用了扩展运算符。该运算 ...
最新提案
最新提案本章介绍一些尚未进入标准、但很有希望的最新提案。
do 表达式本质上,块级作用域是一个语句,将多个操作封装在一起,没有返回值。
1234{ let t = f(); t = t * t + 1;}
上面代码中,块级作用域将两个语句封装在一起。但是,在块级作用域以外,没有办法得到t的值,因为块级作用域不返回值,除非t是全局变量。
现在有一个提案,使得块级作用域可以变为表达式,也就是说可以返回值,办法就是在块级作用域之前加上do,使它变为do表达式,然后就会返回内部最后执行的表达式的值。
1234let x = do { let t = f(); t * t + 1;};
上面代码中,变量x会得到整个块级作用域的返回值(t * t + 1)。
do表达式的逻辑非常简单:封装的是什么,就会返回什么。
12345// 等同于 <表达式>do { <表达式>; }// 等同于 <语句>do { <语句> }
do表达式的好处是可以封装多个语句,让程 ...
正则的扩展
正则的扩展RegExp 构造函数在 ES5 中,RegExp构造函数的参数有两种情况。
第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。
123var regex = new RegExp("xyz", "i");// 等价于var regex = /xyz/i;
第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷贝。
123var regex = new RegExp(/xyz/i);// 等价于var regex = /xyz/i;
但是,ES5 不允许此时使用第二个参数添加修饰符,否则会报错。
12var regex = new RegExp(/xyz/, "i");// Uncaught TypeError: Cannot supply flags when constructing one RegExp from another
ES6 改变了这种行为。如果RegExp构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且,返回的正则表达式会忽略 ...