UDN-企业互联网技术人气社区

板块导航

浏览  : 1280
回复  : 0

[干货] 使用ES6新特性开发微信小程序(10)

[复制链接]
舞操的头像 楼主
发表于 2017-1-6 21:26:20 | 显示全部楼层 |阅读模式
  可子类化的内建对象(Subclassable Built-ins)

  在ES6中,像Array,Date和Dom元素这样的内建对象都可以被子类化。

  1.   class MyArray extends Array {

  2.   constructor(...args) {

  3.   super(...args);

  4.   }

  5.   }

  6.   var arr = new MyArray();

  7.   arr[1] = 12;

  8.   console.log(arr.length == 2); // 输出: true
复制代码


  通过子类工厂实现简单的合成器(Simple mixins via subclass factories)

  mixin在JavaScript里可以看作是一种从别的对象"借用"功能的方法。每一个新定义的对象都有一个 prototype属性,其他的对象就可以从这里"借用"功能。这里的功能可以是一个属性,也可以是一个方法。

  Mixin支持在一个系统中降解功能的重复性,增加功能的重用性。在一些应用程序也许需要在所有的对象实体共享行为的地方,我们能够通过在一个Mixin中维护这个共享的功能,来很容易的避免任何重复,而因此专注于只实现我们系统中真正彼此不同的功能。

  在 ES6 中,我们可以采用全新的基于类继承的 “mixin” 模式设计更优雅的“语义化”接口,这是因为 ES6 中的 extends 可以继承动态构造的类,这一点和其他的静态声明类的编程语言不同。当 ES6 类继承另一个类,被继承的类可以是通过任意表达式创建的动态类。这个特性可以允许实现一种合成器模式,用一个函数来将一个类 C 映射到一个新的继承了C的类。

  mixin 式继承的基本形式:

  1.   const decorator = Sup => class extends Sup {

  2.   ...

  3.   }

  4.   class MyClass extends decorator(SuperClass) {

  5.   }
复制代码


  用 mixin 实现 Serilizable

  1.   // mixin

  2.   const Serializable = Sup => class extends Sup {

  3.   constructor(...args) {

  4.   super(...args);

  5.   if (typeof this.constructor.stringify !== "function") {

  6.   throw new ReferenceError("Please define stringify method to the Class!");

  7.   }

  8.   if (typeof this.constructor.parse !== "function") {

  9.   throw new ReferenceError("Please define parse method to the Class!");

  10.   }

  11.   }

  12.   toString() {

  13.   return this.constructor.stringify(this);

  14.   }

  15.   }

  16.   class Person {

  17.   constructor(name, age, gender) {

  18.   Object.assign(this, { name, age, gender });

  19.   }

  20.   }

  21.   class Employee extends Serializable(Person) {

  22.   constructor(name, age, gender, level, salary) {

  23.   super(name, age, gender);

  24.   this.level = level;

  25.   this.salary = salary;

  26.   }

  27.   static stringify(employee) {

  28.   let { name, age, gender, level, salary } = employee;

  29.   return JSON.stringify({ name, age, gender, level, salary });

  30.   }

  31.   static parse(str) {

  32.   let { name, age, gender, level, salary } = JSON.parse(str);

  33.   return new Employee(name, age, gender, level, salary);

  34.   }

  35.   }

  36.   let person = new Person("john", 22, "m");

  37.   console.log(person); // 输出:Person {name: "john", age: 22, gender: "m"}

  38.   let employee = new Employee("jane", 25, "f", 1, 1000);

  39.   let employee2 = Employee.parse(employee + "");

  40.   console.log(employee2); // 输出:Employee {name: "jane", age: 25, gender: "f", level: 1, salary: 1000}

  41.   console.log(employee2 instanceof Employee); // 输出:true

  42.   console.log(employee2 instanceof Person); // 输出:true

  43.   console.log(employee == employee2); // 输出:false
复制代码


  上面的代码,我们用 ES6 的类继承实现了 Serializable,它检查当前实例的类上是否有定义 stringify 和 parse 静态方法,如果有,使用静态方法重写 toString 方法,如果没有,则在实例化对象的时候抛出一个异常。然后通过 class Employ extends Serializable(Person) 来实现可序列化,在这里我们没有可序列化 Person 本身,而将 Serializable 在语义上变成一种修饰,即 Employee 是一种可序列化的 Person。

  使用weakmaps实现私有实例成员(Private instance members with weakmaps)

  Weakmaps解决了私有数据成员的遗留问题。首先,再也没有必自己生成一个唯一的ID了,因为该对象实例本身就是一个唯一ID。其次,当一个对象实例被垃圾回收,绑到该实例中的weakmap中所有数据也会被回收。

  1.   var Shape = (function() {

  2.   var privateData = new WeakMap();

  3.   function Shape(name) {

  4.   privateData.set(this, { name: name });

  5.   }

  6.   Shape.prototype.getName = function() {

  7.   return privateData.get(this).name;

  8.   };

  9.   return Shape;

  10.   }());

  11.   var shape = new Shape('Rectangle');

  12.   console.log(shape.getName()); // 输出:Rectangle

  13.   console.log(shape.name); // 输出:undefined

  14.   console.log(shape.privateData); // 输出:undefined
复制代码


  privateData在这个例子中是一个WeakMap的实例 。当一个新的Shape被创建时,一个weakmap的条目会被创建用来以便该实例来保存包含私有数据的对象。在weakmap中最关键的是this ,即使对于开发者来说获取一个Shape对象的引用是微不足道的一件事,他们也无法从实例外来访问到privateData,所以,数据被从麻烦制造者手中安全保护了。任何想要操纵私有数据的方法只能够通过传入实例的this ,从而拿到返回的对象。在这个例子中, getName()会获取对象并返回name属性的值。

  尾调用优化(Tail-call optimization)

  尾调用(Tail Call)是函数式编程的一个重要概念,是指某个函数的最后一步是调用另一个函数。

  尾调用优化是为了避免不断保留和创建新的调用栈,而在函数最后一步调用另一个函数。最后一步的意义就在于:不需要保留当前函数的执行环境,在调用的下一个函数执行完毕并给出返回值后,直接再返回,类似于pipe。

  函数调用自身,称为递归。如果尾调用自身,就称为尾递归。尾递归(Tail-recursion)就是利用尾调优化的特性,从语言机制上进行递归操作的优化,防止堆栈溢出(stack overflow)。

  "尾调用优化"对递归操作意义重大,所以一些函数式编程语言将其写入了语言规格。ES6也是如此,第一次明确规定,所有 ECMAScript 的实现,都必须部署"尾调用优化"。这就是说,在 ES6 中,只要使用尾递归,就不会发生栈溢出,相对节省内存。

  递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误(stack overflow)。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。

  下面代码是一个阶乘函数,计算n的阶乘,最多需要保存n个调用记录,复杂度 O(n)

  1.   function factorial(n) {

  2.   if (n === 1) {

  3.   return 1;

  4.   }

  5.   return n * factorial(n - 1);

  6.   }

  7.   console.log(factorial(10)); // 输出: 3628800
复制代码


  如果改成尾递归调用,只保留一个调用记录,复杂度 O(1)

  1.   function factorial2(n, total = 1) {

  2.   if (n === 1) {

  3.   return total;

  4.   }

  5.   return factorial2(n - 1, n * total);

  6.   }

  7.   console.log(factorial2(10)); // 输出: 3628800
复制代码


  计算fibonacci数列,能充分说明尾递归优化的重要性

  1.   function fibonacci(n) {

  2.   if (n <= 1) {

  3.   return 1

  4.   };

  5.   return fibonacci(n - 1) + fibonacci(n - 2);

  6.   }

  7.   console.log(fibonacci(10)); // 输出: 89
复制代码


  使用尾递归优化过的fibonacci 递归算法

  1.   function fibonacci2(n, ac1 = 1, ac2 = 1) {

  2.   if (n <= 1) {

  3.   return ac2

  4.   };

  5.   return fibonacci2(n - 1, ac2, ac1 + ac2);

  6.   }

  7.   console.log(fibonacci2(10)); // 输出: 89

  8.   console.log(fibonacci2(100)); // 输出: 573147844013817200000

  9.   console.log(fibonacci2(1000)); // 输出: 7.0330367711422765e+208

  10.   console.log(fibonacci2(2000)); // 输出: Infinity

  11.   console.log(fibonacci2(10000)); // 输出: RangeError: Maximum call stack size exceeded
复制代码


  自定义错误类(Custom Errors)

  Error是JavaScript中的错误类,它同时也是一个构造函数,可以用来创建一个错误对象。Error实例会在发生运行进错误时抛出,Error像其它对象一样,也可以由用户自定义创建。

  ES6通过派生实现自定义错误类

 
  1.  class MyError extends Error {

  2.   constructor(message) {

  3.   super(message);

  4.   this.message = message;

  5.   this.name = 'MyError';

  6.   }

  7.   }

  8.   var error = new Error(" Error occurred");

  9.   console.log(error.message); // 输出: Error occurred

  10.   var myerror = new MyError("Error occurred");

  11.   console.log(myerror.message); // 输出: Error occurred
复制代码


  其他

  完整代码:https://github.com/guyoung/GyWxappCases/tree/master/ES6

原文作者:佚名  来源:开发者头条
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部