1. 类定义
- 类的定义分为类声明和类选表达式
 - 类表达式在它们被求值前不能引用
 - 类定义与函数定义的区别: 函数表达式可以提升, 类定义不能
 - 另一个不同点, 函数受函数作用与限制; 而类受块作用域限制 ```javascript // 类声明 class Animal {}
 
// 类表达式 const animal = class {}
// 变量的提升 console.log(fn) // undefined var fn = function () {}
console.log(c) // 报错 var c = class {}
// 另一个不同点, 函数受函数作用与限制; 而类受块作用域限制 { function fn () {} class ClassName {} } console.log(fn) // 能够打印出fn console.log(ClassName) // 出错
**类构成**```javascript// 空类定义,有效class Foo {}// 有构造函数的类 有效class Bar {constructor() {}}// 有获取函数的类 有效class Bar {get myBzr () {}}// 有静态方法的类 有效class Qux {static myQux () {}}
2. 类的构造函数
类的构造函数: constructor() 用在类内部创建类的构造函数。 constructor() 在使用 new操作符创建类的实例时调用。
实例化:
(new 的实例化过程很重要)
讲了使用 new 操作符实例化后的操作; 意味着会跟着调用 constructor()构造函数;
 new调用类的构造函数会执行以下操作 
- 在内存种创建一个新对象
 - 这个对象内部的 
[[Prototype]]指针被赋值为构造函数(constructor)的prototype(原型) 属性 - 构造函数 
constructor内部的this被赋值给这个新对象 (即 this 指向新对象) - 执行构造函数
constructor内部的代码 (给新对象添加属性) - 如果构造函数返回非空对象, 则返回该对象; 否则,返回刚创建的对象
 
- 在类实例化时,可以传入参数作为构造函数的参数。
 - 可以使用 
instanceof检测实例 与类是否具有关联 - 类的构造函数 
class Animal {}与 构造函数function Person () {}的区别- 调用类构造函数必须使用 
new操作符, 不使用new操作符会报错 - 而普通构造函数不适用 
new调用, 则它们就以全局的this(通常时window) 作为内部对象 
 - 调用类构造函数必须使用 
 
class Person {constructor(name) {this.foo = 'foo';if (name) {return {bar: 'bar'}}}}let p1 = new Person(),p2 = new Person('张三');console.log(p1) // Person { foo: 'foo' }console.log(p1 instanceof Person) // trueconsole.log(p2) // { bar: 'bar' } 返回的只是一个普通的对象console.log(p2 instanceof Person) // false//function Person () {}class Animal {}let p = Person(); // 把window 作为 this 来构建实例let a = Animal(); // 报错
把类当成一个特殊的函数
- 类的本质就是一个 函数  ;使用 
typeof检测返回function - 类表示符有 
prototype属性,而这个原型也有一个constructor属性指向类自身 - 可以使用 
instanceof检查构造函数原型是否存在于实例的原型链中 - 类于立即调用函数表达式相似,类也可以立即实例化 ```javascript }class Person {}; console.log(typeof Person); // function
 
// 第二点 let person = new Person();
console.log(Person.prototype); // 指向 constructor 类的构造函数 console.log(Person === Person.prototype.constructor); //true
// 类也可以立即实例化 let p = new class Foo { constructor(x) { console.log(x) } }(“这是传入的参数”)
<a name="PwbIn"></a>## 3. 实例、原型、类成员<a name="sDvZm"></a>#### 实例成员- 创建出来的实例_相互独立,实例不会再原型上共享属性_```javascript// ● 创建出来的实例相互独立,实例不会再原型上共享属性class Person {constructor() {this.name = new String('Jack');this.sayName = () => console.log(this.name)}}let p1 = new Person(),p2 = new Person();console.log(p1.name === p2.name) // falseconsole.log(p1.sayName === p2.sayName) // false// 说明了不同实例 相互独立
原型方法于访问器
- 定义属性或方法时,在类中 定义在 
constructor()构造函数中,和类本身是不一样的- 定义在类本身, 都会出现在 类的原型上
 - 定义在构造函数中, 都会出现在不同的实例上
 
 - 不能直接在类中添加原始值, 不然会报错
 - 类方法等同于对象属性, 可以使用 
字符串、符号、计算的值作为键- 例如类的方法名 
[symbolKey](){}['computed' + 'Key']() {} 
 - 例如类的方法名 
 - 类定义同样支持获取设置访问器, 设置访问器 
getter | setter```javascript class Person { constructor() { // 定义在实例上 this.locate = () => console.log(‘constructor’); } 
// 定义在类的原型上 locate() { console.log(‘prototype’); } }
let p1 = new Person(), p2 = new Person();
console.log(p1) console.log(p1.locate()) // constructor
console.log(Person.prototype.locate()) // prototype
// ● 不能直接在类中添加原始值
class Person { name: ‘Yellowsea’ } // 这样会报错
// ● 类定义同样支持获取设置访问器, 设置访问器 getter | setter class Person { … get name () { return this.name } set name (Val) { this.name = Val } }
<a name="kkAUx"></a>#### 静态类方法静态方法, 在类中使用 `static` 关键字定义静态方法或静态属性- 静态成员每一个类上只能有一个- 静态成员必须要使用`static`关键字作为前缀- 静态方法只能通过类本身来访问- 子类通过 `super().xxx()`调用静态方法- 在类外部添加数据成员 或者 在原型上定义数据成员```javascriptclass Person {static sayHello() {console.log('Hello');}}// 通过 Person访问Person.sayHello(); // Hello// ● 在类外部添加数据成员 或者 在原型上定义数据成员class Person {sayName() {console.log(`${Person.name} is ${Person.greeting}`);}}Person.greeting = 'My name is';Person.name = 'Red';const p = new Person();p.sayName() // Person is My name is
4. 继承
ES6新增的原型继承机制,原理同样使用的是 原型链
继承基础
- 继承使用的是 
extends关键字,可以继承任何拥有[[Construct]]和原型链的对象 - 继承不仅可以继承类, 同样可以继承普通的构造函数
 
class Vehicle {}class Bus extends Vehicle {}let b = new Bus();console.log(b instanceof Bus); // trueconsole.log(b instanceof Vehicle); // true// 继承普通构造函数function Person() {}class Engineer extends Person {}console.log(new Engineer() instanceof Person); // true
构造函数和、super()
- 派生类通过使用
super关键字引入它们的原型。super关键字只能在派生类中使用 - 在类构造函数中使用 
super可以调用父类构造函数 super的作用,简单来说在继承的类构造函数类中调用父类的构造函数- 在父类定义的静态方法,同样可以使用 
super().xxx进行调用 ```javascript 
class Vehicle { constructor() { this.hasEngine = true; } }
class Bus extends Vehicle { constructor() { // 不要在调用 super() 之前引入 this,否则会报错。 super(); // 执行 super() 后, 相当于调用了 Vehicle 的构造函数。给属性赋值 console.log(this instanceof Vehicle); // true console.log(this); // Bus { hasEngine: true } // 此时的this指向的是Bus } }
new Bus();
```
super的几个注意事项
super只能在派生类的构造函数和静态方法中使用- 不能单独使用
super,要么用它调用构造函数,要么用它引用静态方法 - 调用
super()会调用父类的构造函数, 并将返回的实例赋值给this super如果调用构造函数,如果需要给父类构造函数传参,需要手动设置传入参数- 如果没有定义类的构造函数, 在实例化派生类时会调用 
super(), 而且传入的参数会传给父类的构造函数 - 在类构造函数中, 不能在调用
super()之前引用this - 如果派生类中显示定义了构造函数,则要么必须在其中调用 
super(), 要么必须在其中返回一个对象 
