• ES6 的类,可以看作 ES5 构造函数 的另一种写法。
    • 基本上,ES6 的class可以看作只是一个语法糖。它的绝大部分功能,ES5 都可以做到

      基本使用

      ```javascript // 案例一 // ES5的构造函数 function MyGood({ name = ‘’, price = 0 }) { this.name = name; this.price = price; this.run = () => { console.log(‘run’) } }

MyGood.prototype.say = function () { console.log(‘say’) }

let good = new MyGood({name: ‘car’, price: 1000});

/**

  • new MyGood({name: ‘car’, price: 1000}) ——>
  • {
  • proto: MyGood.prototype,
  • constructor: MyGood,
  • name: ‘car’,
  • price: 1000,
  • run: () => { console.log(‘run’) }
  • } */

// 写成ES6的类 class MyGood { constructor(params) { this.name = params.name || ‘’; this.price = params.price || 0; this.run = () => { console.log(‘run’) } } say() { console.log(‘say’) } }

  1. <a name="cjnA8"></a>
  2. ## 静态方法和动态方法
  3. - 静态方法:该方法不会被实例继承,而是直接通过类来调用
  4. - 动态方法:被实例继承,通过实例来调用
  5. ```javascript
  6. // 案例二:构造函数的静态方法和动态方法
  7. // ES5的写法
  8. function MyGood(params) {
  9. this.name = params.name || '';
  10. this.price = params.price || 0;
  11. this.run = () => { console.log('run') }
  12. }
  13. // 静态方法:该方法不会被实例继承,而是直接通过类来调用
  14. MyGood.say = function () {
  15. console.log('MyGood say')
  16. }
  17. // 动态方法:被实例继承,通过实例来调用
  18. MyGood.prototype.say = function () {
  19. console.log('instance say')
  20. }
  21. let good = new MyGood({ name: 'car', price: 1000 });
  22. MyGood.say(); // 'MyGood say'
  23. good.say(); // 'instance say'
  24. // ES6的写法
  25. class MyGood {
  26. constructor(params) {
  27. this.name = params.name || '';
  28. this.price = params.price || 0;
  29. this.run = () => { console.log('run') }
  30. }
  31. // 动态方法
  32. say() {
  33. console.log('instance say')
  34. }
  35. // 静态方法
  36. static say() {
  37. console.log('MyGood say')
  38. }
  39. }

静态属性和动态属性

  • 静态方法:该属性不会被实例继承,而是直接通过类来获取
  • 动态方法:被实例继承,通过实例来获取 ```javascript // ES5的写法 function MyClass() {} MyClass.count = 0;

// ES6的写法 class MyClass { static count = 0; } // 或者 class MyClass {} MyClass.count = 0;

  1. <a name="KZQpU"></a>
  2. ## 私有方法和私有属性
  3. - 私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问。
  4. - 这是常见需求,有利于代码的封装,但 ES6 不提供,只能通过变通方法模拟实现
  5. - TS 才有`private 和 public`关键字
  6. <a name="uQJ4L"></a>
  7. ### 现有的解决方法
  8. - 命名上加以区分
  9. - 比如加下划线
  10. ```javascript
  11. class MyClass {
  12. // 公有方法
  13. say() {
  14. console.log('public say')
  15. }
  16. // 私有方法
  17. __say() {
  18. console.log('private say')
  19. }
  20. }
  • 利用Symbol值的唯一性,将私有方法的名字命名为一个Symbol值
    • Reflect.ownKeys()依然可以拿到它们 ```javascript let s1 = Symbol(‘say’); class MyClass { // 公有方法 say() { console.log(‘public say’) } // 私有方法 s1 { console.log(‘private say’) } }

// 通过Reflect.ownKeys()获取 Reflect.ownKeys(MyClass.prototype); // [‘say’, Symbol(‘say’)]

  1. <a name="Cnihk"></a>
  2. ### 私有属性的提案(未实现)
  3. - 在`属性名/方法名`之前加`#`,表示是类的`私有属性/私有方法`
  4. ```javascript
  5. class Foo {
  6. #a;
  7. #b;
  8. constructor(a, b) {
  9. this.#a = a;
  10. this.#b = b;
  11. }
  12. #sum() {
  13. return this.#a + this.#b;
  14. }
  15. printSum() {
  16. console.log(this.#sum());
  17. }
  18. }

类的继承

  • ES5 的继承,实质是先创造子类的实例对象this,然后再通过Parent.apply(this)将父类的方法添加到this
    • Parent.apply(this)先写后写,问题不大
  • ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this ```javascript // 案例一:如果子类没有定义constructor方法,这个方法会被默认添加 class Point {}

class ColorPoint extends Point {}

// 等同于 class ColorPoint extends Point { constructor(args) { super(args); } }

  1. ```javascript
  2. // 案例二:
  3. // ES5 实现继承(寄生组合式继承)
  4. function Father(props) {
  5. this.name = props.name || '';
  6. this.age = props.age || 0;
  7. }
  8. // 在声明函数的时候,会自动创建一个prototype属性,我们管他叫函数原型对象,一般用来存放实例公用的方法
  9. function Son(props) {
  10. this.money = props.money || 100;
  11. Father.call(this, props); // 写在后面也一样
  12. }
  13. // 用来改变subClass的原型的函数
  14. function inheritPrototype(subClass, superClass) {
  15. subClass.prototype = Object.create(superClass.prototype);
  16. subClass.prototype.constructor = subClass;
  17. }
  18. inheritPrototype(Son, Father);
  19. var test = new Son({ name: 'John', age: 18, money: 50 });
  20. console.log(test instanceof Father);// true
  21. console.log(test instanceof Son); // true
  22. /**
  23. * ES5 中
  24. * 一开始声明Son的时候,自动创建的prototype
  25. * Son.prototype = {
  26. * __proto__: Object.prototype,
  27. * constructor: Son(props) {...},
  28. * }
  29. *
  30. * 后来通过inheritPrototype改变Son的prototype
  31. * Son.prototype = {
  32. * __proto__: Father.prototype,
  33. * constructor: Son
  34. * }
  35. *
  36. * 根据new执行的步骤
  37. * new Son({ name: 'John', age: 18, money: 50 }) ——>
  38. * {
  39. * __proto__: Son.prototype,
  40. * constructor: Son
  41. * name: 'John',
  42. * age: 18,
  43. * money: 50
  44. * }
  45. */
  46. // ES6实现继承
  47. class Father {
  48. constructor(props) {
  49. this.name = props.name || '';
  50. this.age = props.age || 0;
  51. }
  52. }
  53. class Son extends Father {
  54. constructor(props) {
  55. super(props);
  56. this.money = props.money || 100;
  57. }
  58. }
  59. let test = new Son({ name: 'John', age: 18, money: 50 });
  60. console.log(test instanceof Father);// true
  61. console.log(test instanceof Son); // true
  62. /**
  63. * ES6 中
  64. *
  65. * 声明Father,没使用extends
  66. * Father.prototype = {
  67. * __proto__: Object.prototype,
  68. * constructor: Father
  69. * }
  70. *
  71. * 声明Son时,使用extends Father
  72. * Son.prototype = {
  73. * __proto__: Father.prototype,
  74. * constructor: Son
  75. * }
  76. *
  77. * new Son({ name: 'John', age: 18, money: 50 }) ——>
  78. * {
  79. * __proto__: Son.prototype,
  80. * constructor: Son
  81. * name: 'John',
  82. * age: 18,
  83. * money: 50
  84. * }
  85. */
  • 使用 ES6 的 extends继承时,父类的静态方法,也会被子类继承 ```javascript // 案例三 class A { static hello() { console.log(‘hello world’); } } class B extends A { }

B.hello() // hello world

  1. <a name="zobdz"></a>
  2. ### 细说super
  3. - 如果super作为对象,用在静态方法之中,这时super将指向父类,而不是父类的原型对象
  4. - 如果`super`作为函数,调用时,代表父类的构造函数
  5. - `super`虽然代表了`父类A`的构造函数,但返回的是`子类B`的实例
  6. - 即`super`内部的`this`指的是`B`的实例
  7. - 如果`super`作为对象
  8. - 用在子类静态方法之中,这时`super`将指向父类
  9. - 在子类普通方法之中,这是`super`指向父类的原型对象
  10. ```javascript
  11. // 案例一:当super作为函数,调用时
  12. class A {}
  13. class B extends A {
  14. consturctor(params) {
  15. // 此时的super(params) 相当于 A.prototype.constructor.call(this, params)
  16. super(params)
  17. }
  18. }
  1. // 案例二:当super 作为对象时
  2. class A {
  3. static print() { console.log('static', this.x); }
  4. print() { console.log(this.x); }
  5. }
  6. class B extends A {
  7. constructor() {
  8. super();
  9. this.x = 2;
  10. }
  11. m() { super.print(); }
  12. static x = 3
  13. static m() { super.print(); }
  14. }
  15. B.m(); // static 3
  16. let instanceB = new B();
  17. instanceB.m(); // 2