# Class

* [class](/directory-2/class.md#class)
  * [基本语法](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#基本语法)
  * [constructor方法](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#constructor方法)
  * [类的实例对象](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#类的实例对象)
  * [this的指向](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#this的指向)
  * [Class的继承](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#class的继承)
  * [类的prototype属性和\_\_proto\_\_属性](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#类的prototype属性和__proto__属性)
  * [Extends 的继承目标](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#extends-的继承目标)
    * [子类继承Object类。](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#子类继承object类)
    * [不存在任何继承。](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#不存在任何继承)
    * [子类继承null。](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#子类继承null)
  * [super](/directory-2/class.md#super)
  * [实例的\_\_proto\_\_属性](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#实例的__proto__属性)
  * [Class的取值函数（getter）和存值函数（setter）](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#class的取值函数getter和存值函数setter)
  * [Class 的 Generator 方法](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#class-的-generator-方法)
  * [Class 的静态方法](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#class-的静态方法)
  * [new.target属性](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#newtarget属性)
  * [Mixin模式的实现](https://note.niefee.com/directory-2/pages/-LjTb6fLJpCNmHEuicgP#mixin模式的实现)

## class

### 基本语法

ES6引入`Class`这个概念，作为对象模板。

```javascript
//es5
function PersonType(name) {
    this.name = name;
}

PersonType.prototype.sayName = function() {
    console.log(this.name);
};

let person = new PersonType("Nicholas");
person.sayName();   // 输出 "Nicholas"

//ES6

class PersonClass {

    // 等价于 PersonType 构造器
    constructor(name) {
        this.name = name;
    }

    // 等价于 PersonType.prototype.sayName
    sayName() {
        console.log(this.name);
    }
}
let person = new PersonClass("Nicholas");
person.sayName();   // 输出 "Nicholas"
```

ES5的构造函数`Point`，对应ES6的`Point`类的构造方法。

构造函数的`prototype`属性，在ES6的“类”上面继续存在。

```javascript
class Point {
    constructor(){
    // ...
    }

    toString(){
    // ...
    }

    toValue(){
    // ...
    }
}

// 等同于

Point.prototype = {
  toString(){},
  toValue(){}
};
```

`prototype`对象的`constructor`属性，直接指向“类”的本身。

```javascript
Point.prototype.constructor === Point // true
```

### constructor方法

`constructor`方法是类的默认方法，通过`new`命令生成对象实例时，自动调用该方法。

`constructor`方法默认返回实例对象（即`this`），完全可以指定返回另外一个对象。

```javascript
class Foo {
  constructor() {
    return Object.create(null);
  }
}

new Foo() instanceof Foo
// false
```

### 类的实例对象

类的调用的要加上`new`，类的所有实例共享一个原型对象。

```javascript
var p1 = new Point(2,3);
var p2 = new Point(3,2);

p1.__proto__.printName = function () { return 'Oops' };

p1.printName() // "Oops"
p2.printName() // "Oops"

var p3 = new Point(4,2);
p3.printName() // "Oops"
```

### this的指向

类的方法内部如果含有`this`，它默认指向类的实例。

```javascript
class Logger {
  printName(name = 'there') {
    this.print(`Hello ${name}`);
  }

  print(text) {
    console.log(text);
  }
}
const logger = new Logger();
logger.printName();
//Hello there
```

### Class的继承

Class之间可以通过`extends`关键字实现继承。

```javascript
class Point {
    constructor(x,y,color){
        this.x=x;
        this.y=y;
        this.color=color;
    }
    chooseColor(){
        console.log('color:',this.color);
    }
}

class ColorPoint extends Point {
  constructor() {
      super(1,2,'blue');
  }
  toString(){
      return 'ColorPoint:'+super.color
  }
}

var cp=new ColorPoint();
cp.chooseColor()
//VM2425:8 color: blue
```

`super`表示父类的构造函数，新建父类的`this`对象。子类没有调用，会报错。

### 类的prototype属性和\_\_proto\_\_属性

1. 子类的`__proto__`属性，表示构造函数的继承，总是指向父类。
2. 子类`prototype`属性的`__proto__`属性，表示方法的继承，总是指向父类的`prototype`属性。

```javascript
class A {
}

class B extends A {
}

B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
```

### Extends 的继承目标

#### 子类继承Object类。

```javascript
class A extends Object {
}

A.__proto__ === Object // true
A.prototype.__proto__ === Object.prototype // true
```

`A`其实就是构造函数`Object`的复制，`A`的实例就是`Object`的实例。

#### 不存在任何继承。

```javascript
class A {
}

A.__proto__ === Function.prototype // true
A.prototype.__proto__ === Object.prototype // true
```

这种情况下，`A`作为一个基类（即不存在任何继承），就是一个普通函数，所以直接继承`Funciton.prototype`。调用后返回空对象，指向造函数（Object）的`prototype`属性。

#### 子类继承null。

```javascript
class A extends null {
}

A.__proto__ === Function.prototype // true
A.prototype.__proto__ === undefined // true
```

### super

`super`代表父类`A`的构造函数，返回子类`b`的实例。 `spuer`内部`this`指向`B`。

```javascript
class A {
  constructor() {
    console.log(new.target.name);
  }
}
class B extends A {
  constructor() {
    super();
  }
}
new A() // A
new B() // B
```

`super`作为对象时，在普通方法中，指向父类的原型对象；在静态方法中，指向父类。

通过`super`调用父类的方法时，`super`会绑定子类的`this`。

```javascript
class A {
  constructor() {
    this.x = 1;
  }
  print() {
    console.log(this.x);
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
  }
  m() {
    super.print();
    //new A().print.call(this);
  }
}

let b = new B();
b.m() // 2
```

### 实例的\_\_proto\_\_属性

子类实例的\_\_proto\_\_属性的\_\_proto\_\_属性，指向父类实例的\_\_proto\_\_属性。也就是说，子类的原型的原型，是父类的原型。

```javascript
var p1 = new Point(2, 3);
var p2 = new ColorPoint(2, 3, 'red');

p2.__proto__ === p1.__proto__ // false
p2.__proto__.__proto__ === p1.__proto__ // true
```

### Class的取值函数（getter）和存值函数（setter）

```javascript
class MyClass {
  constructor() {
    // ...
  }
  get prop() {
    return 'getter';
  }
  set prop(value) {
    console.log('setter: '+value);
  }
}

let inst = new MyClass();

inst.prop = 123;
// setter: 123

inst.prop
// 'getter'
```

`prop`属性有对应的存值函数和取值函数，因此赋值和读取行为都被自定义了。

### Class 的 Generator 方法

```javascript
class Foo {
  constructor(...args) {
    this.args = args;
  }
  * [Symbol.iterator]() {
    for (let arg of this.args) {
      yield arg;
    }
  }
}

for (let x of new Foo('hello', 'world')) {
  console.log(x);
}
// hello
// world
```

Foo类的`Symbol.iterator`方法前有一个星号，表示该方法是一个 Generator 函数。`Symbol.iterator`方法返回一个Foo类的默认遍历器

### Class 的静态方法

如果在一个方法前，加上`static`关键字，就表示该方法不会被实例继承，而是直接通过类来调用。父类的静态方法，能被子类继承。也可以在`super`上调用。

```javascript
class Foo {
  static classMethod() {
    return 'hello';
  }
}

Foo.classMethod() // 'hello'

var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function
```

ES6只用静态方法，没有静态属性。

### new\.target属性

`new`命令作用于的那个构造函数，子类继承父类时，`new.target`会返回子类。

```javascript
class Rectangle {
  constructor(length, width) {
    console.log(new.target === Rectangle);
    this.length = length;
    this.width = width;
  }
}

var obj = new Rectangle(3, 4); // 输出 true
```

### Mixin模式的实现

`Mixin`模式指的是，将多个类的接口“混入”（mix in）另一个类。

```javascript
function mix(...mixins) {
  class Mix {}

  for (let mixin of mixins) {
    copyProperties(Mix, mixin);
    copyProperties(Mix.prototype, mixin.prototype);
  }

  return Mix;
}

function copyProperties(target, source) {
  for (let key of Reflect.ownKeys(source)) {
    if ( key !== "constructor"
      && key !== "prototype"
      && key !== "name"
    ) {
      let desc = Object.getOwnPropertyDescriptor(source, key);
      Object.defineProperty(target, key, desc);
    }
  }
}

class DistributedEdit extends mix(Loggable, Serializable) {
  // ...
}
```

上面代码的`mix`函数，可以将多个对象合成为一个类。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://note.niefee.com/directory-2/class.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
