- ES6 的类,可以看作 ES5 构造函数 的另一种写法。
 
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’) } }
<a name="cjnA8"></a>## 静态方法和动态方法- 静态方法:该方法不会被实例继承,而是直接通过类来调用- 动态方法:被实例继承,通过实例来调用```javascript// 案例二:构造函数的静态方法和动态方法// ES5的写法function MyGood(params) {this.name = params.name || '';this.price = params.price || 0;this.run = () => { console.log('run') }}// 静态方法:该方法不会被实例继承,而是直接通过类来调用MyGood.say = function () {console.log('MyGood say')}// 动态方法:被实例继承,通过实例来调用MyGood.prototype.say = function () {console.log('instance say')}let good = new MyGood({ name: 'car', price: 1000 });MyGood.say(); // 'MyGood say'good.say(); // 'instance say'// ES6的写法class MyGood {constructor(params) {this.name = params.name || '';this.price = params.price || 0;this.run = () => { console.log('run') }}// 动态方法say() {console.log('instance say')}// 静态方法static say() {console.log('MyGood say')}}
静态属性和动态属性
- 静态方法:该属性不会被实例继承,而是直接通过类来获取
 - 动态方法:被实例继承,通过实例来获取 ```javascript // ES5的写法 function MyClass() {} MyClass.count = 0;
 
// ES6的写法 class MyClass { static count = 0; } // 或者 class MyClass {} MyClass.count = 0;
<a name="KZQpU"></a>## 私有方法和私有属性- 私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问。- 这是常见需求,有利于代码的封装,但 ES6 不提供,只能通过变通方法模拟实现- TS 才有`private 和 public`关键字<a name="uQJ4L"></a>### 现有的解决方法- 命名上加以区分- 比如加下划线```javascriptclass MyClass {// 公有方法say() {console.log('public say')}// 私有方法__say() {console.log('private say')}}
- 利用
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’)]
<a name="Cnihk"></a>### 私有属性的提案(未实现)- 在`属性名/方法名`之前加`#`,表示是类的`私有属性/私有方法````javascriptclass Foo {#a;#b;constructor(a, b) {this.#a = a;this.#b = b;}#sum() {return this.#a + this.#b;}printSum() {console.log(this.#sum());}}
类的继承
- 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); } }
```javascript// 案例二:// ES5 实现继承(寄生组合式继承)function Father(props) {this.name = props.name || '';this.age = props.age || 0;}// 在声明函数的时候,会自动创建一个prototype属性,我们管他叫函数原型对象,一般用来存放实例公用的方法function Son(props) {this.money = props.money || 100;Father.call(this, props); // 写在后面也一样}// 用来改变subClass的原型的函数function inheritPrototype(subClass, superClass) {subClass.prototype = Object.create(superClass.prototype);subClass.prototype.constructor = subClass;}inheritPrototype(Son, Father);var test = new Son({ name: 'John', age: 18, money: 50 });console.log(test instanceof Father);// trueconsole.log(test instanceof Son); // true/*** ES5 中* 一开始声明Son的时候,自动创建的prototype* Son.prototype = {* __proto__: Object.prototype,* constructor: Son(props) {...},* }** 后来通过inheritPrototype改变Son的prototype* Son.prototype = {* __proto__: Father.prototype,* constructor: Son* }** 根据new执行的步骤* new Son({ name: 'John', age: 18, money: 50 }) ——>* {* __proto__: Son.prototype,* constructor: Son* name: 'John',* age: 18,* money: 50* }*/// ES6实现继承class Father {constructor(props) {this.name = props.name || '';this.age = props.age || 0;}}class Son extends Father {constructor(props) {super(props);this.money = props.money || 100;}}let test = new Son({ name: 'John', age: 18, money: 50 });console.log(test instanceof Father);// trueconsole.log(test instanceof Son); // true/*** ES6 中** 声明Father,没使用extends* Father.prototype = {* __proto__: Object.prototype,* constructor: Father* }** 声明Son时,使用extends Father* Son.prototype = {* __proto__: Father.prototype,* constructor: Son* }** new Son({ name: 'John', age: 18, money: 50 }) ——>* {* __proto__: Son.prototype,* constructor: Son* name: 'John',* age: 18,* money: 50* }*/
- 使用 ES6 的 
extends继承时,父类的静态方法,也会被子类继承 ```javascript // 案例三 class A { static hello() { console.log(‘hello world’); } } class B extends A { } 
B.hello() // hello world
<a name="zobdz"></a>### 细说super- 如果super作为对象,用在静态方法之中,这时super将指向父类,而不是父类的原型对象- 如果`super`作为函数,调用时,代表父类的构造函数- `super`虽然代表了`父类A`的构造函数,但返回的是`子类B`的实例- 即`super`内部的`this`指的是`B`的实例- 如果`super`作为对象- 用在子类静态方法之中,这时`super`将指向父类- 在子类普通方法之中,这是`super`指向父类的原型对象```javascript// 案例一:当super作为函数,调用时class A {}class B extends A {consturctor(params) {// 此时的super(params) 相当于 A.prototype.constructor.call(this, params)super(params)}}
// 案例二:当super 作为对象时class A {static print() { console.log('static', this.x); }print() { console.log(this.x); }}class B extends A {constructor() {super();this.x = 2;}m() { super.print(); }static x = 3static m() { super.print(); }}B.m(); // static 3let instanceB = new B();instanceB.m(); // 2
