小言_互联网的博客

《ES6标准入门(阮一峰) 第3版 》读书笔记

382人阅读  评论(0)

一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbol.iterator方法。


  
  1. // yield语句遍历完全二叉树
  2. // 下面是二叉树的构造函数,
  3. // 3个参数分别是左树、当前节点和右树
  4. function Tree(left, label, right){
  5. this.left = left;
  6. this.label = label;
  7. this.right = right;
  8. }
  9. // 下面是中序(inorder)遍历函数。
  10. // 由于返回的是一个便利器,所以要用generator函数。
  11. // 函数体内采用递归算法,所以左树和右树要用yield*遍历
  12. function* inorder(t){
  13. if(t){
  14. yield* inorder(t.left);
  15. yield t.label;
  16. yield* inorder(t.right);
  17. }
  18. }
  19. // 下面生成二叉树
  20. function make(array){
  21. // 判断是否为叶节点
  22. if(array.length == 1) return new Tree( null,array[ 0], null);
  23. return new Tree(make(array[ 0]), array[ 1], make(array[ 2]));
  24. }
  25. let tree = make([[[ 'a'], 'b', [ 'c']], 'd', [[ 'e'], 'f', [ 'g']]]);
  26. // 遍历二叉树
  27. var result = [];
  28. for( let node of inorder(tree)){
  29. result.push(node);
  30. }
  31. console.log(result);

  
  1. var clock = function* (){
  2. while( true){
  3. console.log( 'Tick!');
  4. yield;
  5. console.log( 'Tock!');
  6. yield;
  7. }
  8. }
  9. clock();
  10. // 由于JavaScript是单线程语言,只能保持一个调用栈。引入协程以后,
  11. // 每个任务可以保持自己的调用栈。这样做的最大好书,就是抛出错误的时候,
  12. // 可以找到原始的调用栈。不至于像异步操作的回调函数那样,
  13. // 一旦出错原始的调用栈早就结束。Generator函数是对协程的实现,但属于不完全实现。
  14. // Generator函数可以改善代码运行流程
  15. function* longRunningTask(value){
  16. try{
  17. var value2 = yield step1(value);
  18. var value3 = yield step2(value2);
  19. var value4 = yield step3(value3);
  20. var value5 = yield step4(value4);
  21. // Do something with value4
  22. } catch(e) {
  23. // handle any error from step1 through step4
  24. }
  25. }
  26. // 使用一个函数按次序自动执行所有步骤
  27. scheduler(longRunningTask(initalValue));
  28. function scheduler(task){
  29. var taskobj = task.next(task.value);
  30. // 如果Generator函数未结束,就继续调用
  31. if(!taskObj.done){
  32. task.value = taskObj.value;
  33. scheduler(task);
  34. }
  35. }
  36. // Promise的最大问题是冗余,原来的任务被Promise包装之后,
  37. // 无论什么操作,一眼看去都是很多then的堆积,原来的语义变得很不清楚。 协程:多个线程互相协作,完成异步任务。
  38. // next返回值的value属性石Generate函数向外输出数据;
  39. // next方法还可以接受参数,向Generator函数体内输入数据
  40. function* gen(x){
  41. var y = yield x + 2;
  42. return y;
  43. }
  44. var g = gen( 1);
  45. g.next() //{value:3, done: false}
  46. g.next( 2) //{value:2, done: true}
  47. // 传名调用
  48. function f(m){
  49. return m* 2;
  50. }
  51. f(x+ 5);
  52. // JavaScript语言是传值调用,
  53. // 手动执行其实就是用then方法层层添加回调函数 手写自动执行器
  54. function run(gen){
  55. var g = gen();
  56. function next(data){
  57. var result = g.next(data);
  58. if(result.done){
  59. return result.value;
  60. }
  61. result.value.then( function(data){
  62. next(data);
  63. });
  64. }
  65. next();
  66. }
  67. // Node提供Stream模式读写数据,特点是一次只处理数据的一部分,
  68. // 数据被分成一块一块依次处理,就好像“数据流”一样。
  69. // async函数用一句话来说,它就是Generator函数的语法糖。
  70. // async函数对Generator函数的改进体现在4点:1、自带执行器;2、更好的语义;3
  71. // 更广的适用性:async函数的await命令后面,
  72. // 可以是Promise对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作);
  73. // 4、返回值是Promise:async函数完全可以看作由多个异步操作包装成的一个Promise对象,
  74. // 而await命令就是内部then命令的语法糖。
  75. //

  
  1. // async指定多少毫秒后输出一个值
  2. function timeout(ms){
  3. return new Promise( (resolve) =>{
  4. setTimeout(resolve, ms);
  5. });
  6. }
  7. async function aysncPrice(value, ms){
  8. await timeout(ms);
  9. console.log(value);
  10. }
  11. asyncPrint( 'hello world', 50);
  12. // 如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。
  13. // 这样便于以后添加返回值,以及更改返回值的顺序
  14. // bad
  15. function processInput(input){
  16. return [left, right, top, bottom];
  17. }
  18. // good
  19. function processInput(input){
  20. return {left, right, top, bottom};
  21. }
  22. const {left, right} = processInput(input);
  23. // bad
  24. [ 1, 2, 3].map( function(x){
  25. return x*x;
  26. });
  27. // good
  28. [ 1, 2, 3].map( (x)=>{
  29. return x*x;
  30. });
  31. // best
  32. [ 1, 2, 3].map( x=>x*x);
  33. // 箭头函数取代Function.prototype.bind,不再用self/_this/that绑定this
  34. // bad
  35. // const self = this;
  36. const boundMethod = function(...params){
  37. return method.apply(self,params);
  38. }
  39. // acceptable
  40. const boundMethod = method.bind( this);
  41. // best
  42. const boundMethod = (...params) => method.apply( this, params);

  
  1. // 多个await命令后面的异步操作如果不存在继发关系,最好让它们同时触发
  2. // 写法一
  3. let [foo, bar] = await Promise.all([getFoo(), getBar()]);
  4. // 写法二
  5. let fooPromise = getFoo();
  6. let barPromise = getBar();
  7. let foo = await fooPromise;
  8. let bar = await barPromise;
  9. // 上面两种写法中,getFoo和getBar都是同时触发,这样就会缩短程序的执行时间
  10. // async函数的实现原理就是将Generator函数和自动执行器包装在一个函数里
  11. async function fn(args){
  12. // ...
  13. }
  14. // 等同于
  15. function fn(args){
  16. return spawn( function* (){
  17. // ...
  18. });
  19. }
  20. // spawn函数就是自动执行器
  21. function spawn(genF){
  22. return new Promise( function(resolve, reject){
  23. var gen = genF();
  24. function step(nextF){
  25. try{
  26. var next = nextF();
  27. } catch(e){
  28. return reject(e);
  29. }
  30. if(next.done){
  31. return resolve(next.value);
  32. }
  33. Promise.resolve(next.value).then( function(v){
  34. step( function(){
  35. return gen.next(v);
  36. }), function(e){
  37. step( function(){
  38. return gen.throw(e);
  39. });
  40. }
  41. })
  42. }
  43. step( function(){
  44. return gen.next( undefined);
  45. })
  46. })
  47. }
  48. // aysnc实现:假如某个DOM元素上面,部署了一系列的动画,前一个动画结束,才能开始后一个。
  49. // 如果当中与一个动画出错,就不再继续执行,而返回上一个成功执行的动画的返回值。
  50. async function chainAnimationsAsync(elem, animations){
  51. var ret = null;
  52. try{
  53. for( var anim of animations){
  54. ret = await anim(elem);
  55. }
  56. } catch(e){
  57. /* 忽略错误,继续执行 */
  58. }
  59. return ret;
  60. }
  61. // for await...of循环用于遍历异步的Iterator接口
  62. async function f(){
  63. for await ( const x of createAsyncIterable([ 'a', 'b'])){
  64. console.log(x);
  65. }
  66. }
  67. // 基本上,ES6中的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰,更像面向对象编程的语法而已。
  68. // Symbol值,达到私有方法和私有属性的效果
  69. const bar = Symbol( 'bar');
  70. const snaf = Symbol( 'snaf');
  71. export default class myClass{
  72. // 公有方法
  73. foo(baz){
  74. this[bar](baz);
  75. }
  76. // 私有方法
  77. [bar](baz){
  78. return this[snaf] = baz;
  79. }
  80. }
  81. // 类的方法内部如果含有this,它将默认指向类的实例。一旦单独使用该方法,很可能会报错。
  82. // 父类的静态方法可以被子类继承
  83. class Foo {
  84. static classMethod(){
  85. return 'hello';
  86. }
  87. }
  88. class Bar extends Foo{}
  89. Bar.classMethod() // 'hello
  90. // ES6可以自定义原生数据结构(比如Array、String等)的子类,这是ES5无法做到的。
  91. class MyArray extends Array{
  92. constructor(...args){
  93. super(...args);
  94. }
  95. }
  96. var arr = new MyArray();
  97. arr[ 0] = 12;
  98. arr.length // 1
  99. arr.length = 0;
  100. arr[ 0] // undefined
  101. // 装饰器改写React与Redux库结合代码
  102. class MyReactComponent extends React.Component{}
  103. export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
  104. // 可改写成如下
  105. @connect(mapStateToProps, mapDispatchToProps)
  106. export defulat class MyReactComponent extends React.Component{}
  107. // 由于存在函数提升,修饰器不能用于函数。类是不会提升的,所以就没有这方面的问题。
  108. // 将Mixin写成一个修饰器
  109. export function mixins(...list){
  110. return function(target){
  111. Object.assign(target.prototype, ...list);
  112. }
  113. }
  114. import {mixins} from './mixins';
  115. const Foo = {
  116. foo(){
  117. console.log( 'foo')
  118. }
  119. };
  120. @mixins(Foo)
  121. class MyClass{}
  122. let obj = new MyClass();
  123. obj.foo() // "foo"
  124. // CommonJs模块就是对象,输入时必须查找对象属性
  125. // 如下代码只有运行时才能得到这个对象,称为"运行时加载",导致完全没办法在编译时进行"静态优化"
  126. let {stat,exists,readFile} = require( 'fs');
  127. // ES6"编译时加载"或者叫静态加载
  128. import {stat,exists,readFile} from 'fs';
  129. import { Socket } from 'dgram';
  130. // 严格模式不能使用前缀0表示八进制数,否则报错
  131. // 接口改名
  132. export {foo as myFoo} from "my_module";
  133. // defer是“渲染完再执行”,async是“下载完就执行”。
  134. // CommonJs模块输出的是值的肤质,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
  135. // ES6模块不会缓存结果,而是动态地去被加载的模块取值,并且斌梁总是绑定其所在的模块。
  136. // 总是用Class取代需要prototype的操作。因为Class的写法更简洁,更易于理解。
  137. // bad
  138. function Queue(contents = []){
  139. const value = this._queue[ 0];
  140. this._queue.splice( 0, 1);
  141. return value;
  142. }
  143. // good
  144. class Queue{
  145. constructor(contents = []){
  146. this._queue = [...contents];
  147. }
  148. pop(){
  149. const value = this._queue[ 0];
  150. this._queue.splice( 0, 1);
  151. return value;
  152. }
  153. }
  154. // .eslintrc
  155. {
  156. "extends": "eslint-config-airbnb"
  157. }
  158. // WebGL,就是浏览器与显卡之间的通信接口,为了满足JavaScript与显卡之间大量、实时的数据交换。
  159. // 它们自建的数据通信必须是二进制的,而不能是传统的文本格式。
  160. // 二进制数组并不是真正的数组,而是类似数组的对象
  161. // TypedArray视图与DataView视图的一个区别是,它不是一个构造函数,而是一组构造函数,代表不同的数据格式。TypedArray的数组成员都是同一个数据类型,而DataView的数组成员可以是不同的数据类型。
  162. // 网页canvas元素输出的二进制像素数据就是TypedArray数组
  163. var canvas = document.getElementById( 'myCanvas');
  164. var ctx = canvas.getContext( '2d');
  165. var imageData = ctx.getImageData( 0, 0,canvas.clientWidth,canvas.height);
  166. var unit8ClampedArray = imgaeData.data;
  167. // Websocket可以通过ArrayBuffer发送或接收二级制数据
  168. var websocket = new WebSocket( 'ws://127.0.0.1:8081');
  169. socket.binaryType = 'arraybuffer';
  170. // Wait until socket is open
  171. socket.addEventListener( 'open', function(event){
  172. // send binary data
  173. var typedArray = new Uint8Array( 4);
  174. socket.send(typedArray.buffer);
  175. });
  176. // Receive binary data
  177. socket.addEventListener( 'message', function(event){
  178. var arrayBuffer = event.data;
  179. // ...
  180. });

 


转载:https://blog.csdn.net/taozi550185271/article/details/106339165
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场