本次我领到的任务是:html
在ES6中有一个解构赋值运算符,能够大大方便数据字段的获取。 好比 const [a, b] = [1, 2, 3]; const {name, age} = {name: 'helijia', age: 3}; 上面的语句是咱们经常使用的,但是你能解释为何下面的语句也能正常工做吗? const [a, b] = 'abc'; const {toString: s} = 123; 任务: 1. 解释上面两个解构语句的工做原理 2. 你可以实现自定义类的数组解构吗? 好比: class A = … const a = new A(); const [e1, e2] = a; // 怎么样才能让自定义的类也能支持支持数组的解构呢?
ES5时,处理默认值的惯用法:node
const scale = opts.scale || 1;
如今能够:git
const {scale = 1} = opts;
不过二者并不等价,默认值只会在目标值是undefined时才会生效。es6
const {scale = 1} = {} // scale === 1 const {scale = 1} = {scale: null} // scale === null const {scale = 1} = {scale: undefined} // scale === 1
有个技巧是能够在一条语句内实现变量值的交换。github
原来须要三句话:正则表达式
var tmp = a; var a = b; var b = a;
如今只须要:算法
const [a, b] = [b, a];
这让咱们在实现一些基础算法时更加精练。chrome
在ES5中函数只能返回一个值,有了解构赋值,能够模拟出多个返回值。c#
const [a, b] = f();
固然从设计上说,js的函数的返回值仍是应该是单一的模型比较合适。 数组
很小看到接口层面返回一个数组做为多个值。 可能在编写一些专业领域或DSL应用时会用获得。
而在实现时常常会使用解构赋值带来的便利:
const {name, age} = getInfo();
const [a, , c] = [1, 2, 3]; // a === 1 // c === c
我想到的一个应用是一会儿从正则表达式match对象中取出多个元素。
const re = /^([^=]+)=(.*)$/; const [, key, value] = re.exec('name=helijia'); // key === 'name' // value === 'helijia'
解构赋值运算符配合spread会比较有用。
const {name, age, ...exts} = item; return <Item {...exts} />;
exts对象中并不包含name和age,若是在ES5中要费好几句语句。
数组也支持spread,可是数组自己具备slice等函数,因此通常用不上。
var [head, ...tail] = [1, 2, 3, 4]; console.log(tail); // [2, 3, 4]
对象的解构还支持从新命名,这在名字冲突,或者简化代码时会比较有用。
const item = { artisanNick: '玉米' artisanLevel: 10, artisanType: 3 }; const {artisanNick:nick, artisanLevel:level, artisanType:type} = item;
原来咱们写成
const nick = item.artisanNick; const level = item.artisanLevel; const type = item.artisanType;
可配合默认值一块儿用:
const {a:aa = 10, b:bb = 5} = {a: 3}
这在实际开发中就用的比较多了,好比在React组件开发中:
const Product = ({name, price}) => ( <div> <div>name: {name}</div> <div>price: {price}</div> </div> );
以上描述的特性使用babel编译器就能在主流浏览器中工做,babel对ES6的支持是经过将代码编译成ES5代码来实现的;
而nodejs和chrome原生是直接支持es6的,它们是基于V8引擎在解释器层面支持ES6,所以二者能力是有差别的。
经过babel编译的ES6,最后本质是ES5代码,是静态的,因此只能支持一些语法糖的功能;
下面是一些示例:
// ES6 const [a, b, c, d] = [1, 2, 3, 4]; // 对应的ES5 var a = 1; var b = 2; var c = 3; var d = 4;
// ES6 const list = [1, 2, 3, 4]; const [a, b, c, d] = list; // ES5 var list = [1, 2, 3, 4]; var a = list[0]; var b = list[1]; var c = list[2]; var d = list[3];
// ES6 const {a:aa = 10, b:bb = 5} = {a: 3} // ES5 var _a = { a: 3 }; var _a$a = _a.a; var aa = _a$a === undefined ? 10 : _a$a; var _a$b = _a.b; var bb = _a$b === undefined ? 5 : _a$b;
重命名和默认值的处理。
// ES6 const [a, b, c] = '1234'; // ES5 var _ = '1234'; var a = _[0]; var b = _[1]; var c = _[2];
字符串也当成数组同样处理了,因此恰好正常工做。
其实只要实现迭代器接口,就可以解构。
const set = new Set([1, 2, 3, 4]) const [a, b, c] = set; console.log(a, b, c); // 1 2 3
这段代码在chrome的cosnole和nodejs中都能正常工做,不过在babel中就歇菜了。
由于它编译后的结果为:
var set = new Set([1, 2, 3, 4]); var a = set[0]; var b = set[1]; var c = set[2]; console.log(a, b, c); // undefined undefined undefined
固然Map也是实现了迭代器接口的。
const map = new Map(); map.set('window', window); map.set('document', document); for (const [key, value] of map) { console.log(key + " is " + value); } const [[k1, v1], [k2, v2]] = map; // destructring
再来一个例子:
function* iter() { yield 1; yield 2; yield 3; } const [a, b, c] = iter(); console.log(a, b, c); // 1 2 3
一样这段代码在babel中也不能正常工做。
const [a, b] = 'abc'; const {toString: s} = 123; 任务: 1. 解释上面两个解构语句的工做原理 2. 你可以实现自定义类的数组解构吗?
因此以上两个语句能正常工做,缘由是分场景的,在经过babel编译成ES5和经过解释器直接执行原理是不同的。
babel编译器会把它编译成
// ES6 const [a, b, c] = '1234'; const {toString: s} = "123"; // ES5 var _ = '1234'; var a = _[0]; var b = _[1]; var c = _[2]; var _2 = "123"; var s = _2.toString;
而js引擎执行ES6是由于字符串实现了迭代器接口,以及支持对象属性访问。
对于第2个问题,咱们可让自定义类实现迭代器接口来支持,只是在babel中不能正常工做。
如下是一个示例:
class Random { [Symbol.iterator]() { return { next() { return {value: Math.random(), done: false}; } } } } const random = new Random(); for (const n of random) { if (n > 0.8) { break; } console.log(n); } const [e1, e2, e3, e4] = new Random(); console.log(e1, e2, e3, e4);
看到数组的解构处理,第一步老是取得一个迭代器,而后操做这个迭代器。
从规范中知道,解构赋值操做符对应的元素就是 DestructuringAssignment
,查询V8代码可知,
V8在parser阶段就会把解构赋值语句重写成等效的赋值语句, 这样解释器不须要作修改就能够运行新的语法,也保证了效率。
关键代码片断:
使用了近一年半的Elixir,有许多语言特性另人着迷,其中模式匹配就是一个。
在ES6中引入了和模式匹配语法有点接近的解构赋值(Destructring Assigmnent)语句,可是仅仅是部分精简代码的语法糖,而在语义和表达上并无本质变化。
不过搜索github上,看到已有相关的proposal,以及babel实现的issue,因此借此机会熟悉了解一番。
另外发现一个js库js-pattern-matching,提供了一个函数来支持模式匹配
其中这个JS库在不引入新语法特性的基础上支持较好的模式匹配语法,我以为挺赞的。 它的原理是利用function.toString,获得函数字符串,再生成匹配的新的函数。
我写了几个简单的示例试用了一下,感受还不错,不过在类型匹配时有些BUG。
const match = require('js-pattern-matching'); const sum = (list) => match(list) ( ([x,...xs]) => x + sum(xs), ([]) => 0 ); console.log(sum([])); console.log(sum([1, 2, 3, 4]));
由于要符合语法,因此加个前续v=
,文档说是可改为其余字母。
const fibs = (n) => match(n) ( (v= 0) => 0, (v= 1) => 1, _ => fibs(n - 2) + fibs(n - 1) ); for (let i = 0; i < 10; i++) { console.log(fibs(i)); }
const type = (v) => match(v) ( (Array) => 'array', (Object) => 'object', _ => 'unknow' );
我也看了proposal的语法,感受风格和原来的js差别太大,设计成Expression,能够在任何地方使用,可能会由于功能太强而致使滥用,反而起不到原来模式匹配优雅简洁的目的。
其余人的一些探索,不过这个语法不是很美观。