Skip to content

Commit

Permalink
docs(class): edit class intro
Browse files Browse the repository at this point in the history
  • Loading branch information
ruanyf committed Dec 9, 2020
1 parent 9985f6b commit 3459393
Showing 1 changed file with 19 additions and 17 deletions.
36 changes: 19 additions & 17 deletions docs/class.md
Expand Up @@ -38,9 +38,9 @@ class Point {
}
```

上面代码定义了一个“类”,可以看到里面有一个`constructor`方法,这就是构造方法,而`this`关键字则代表实例对象。也就是说,ES5 的构造函数`Point`,对应 ES6 的`Point`类的构造方法
上面代码定义了一个“类”,可以看到里面有一个`constructor()`方法,这就是构造方法,而`this`关键字则代表实例对象。这种新的 Class 写法,本质上与本章开头的 ES5 的构造函数`Point`是一致的

`Point`类除了构造方法,还定义了一个`toString`方法。注意,定义“类”的方法的时候,前面不需要加上`function`这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。
`Point`类除了构造方法,还定义了一个`toString()`方法。注意,定义`toString()`方法的时候,前面不需要加上`function`这个关键字,直接把函数定义放进去了就可以了。另外,方法与方法之间不需要逗号分隔,加了会报错。

ES6 的类,完全可以看作构造函数的另一种写法。

Expand All @@ -64,7 +64,7 @@ class Bar {
}
}

var b = new Bar();
const b = new Bar();
b.doStuff() // "stuff"
```

Expand Down Expand Up @@ -94,18 +94,20 @@ Point.prototype = {
};
```

在类的实例上面调用方法,其实就是调用原型上的方法。
上面代码中,`constructor()``toString()``toValue()`这三个方法,其实都是定义在`Point.prototype`上面。

因此,在类的实例上面调用方法,其实就是调用原型上的方法。

```javascript
class B {}
let b = new B();
const b = new B();

b.constructor === B.prototype.constructor // true
```

上面代码中,`b``B`类的实例,它的`constructor`方法就是`B`类原型的`constructor`方法。
上面代码中,`b``B`类的实例,它的`constructor()`方法就是`B`类原型的`constructor()`方法。

由于类的方法都定义在`prototype`对象上面,所以类的新方法可以添加在`prototype`对象上面。`Object.assign`方法可以很方便地一次向类添加多个方法。
由于类的方法都定义在`prototype`对象上面,所以类的新方法可以添加在`prototype`对象上面。`Object.assign()`方法可以很方便地一次向类添加多个方法。

```javascript
class Point {
Expand All @@ -120,7 +122,7 @@ Object.assign(Point.prototype, {
});
```

`prototype`对象的`constructor`属性,直接指向“类”的本身,这与 ES5 的行为是一致的。
`prototype`对象的`constructor()`属性,直接指向“类”的本身,这与 ES5 的行为是一致的。

```javascript
Point.prototype.constructor === Point // true
Expand All @@ -145,14 +147,14 @@ Object.getOwnPropertyNames(Point.prototype)
// ["constructor","toString"]
```

上面代码中,`toString`方法是`Point`类内部定义的方法,它是不可枚举的。这一点与 ES5 的行为不一致。
上面代码中,`toString()`方法是`Point`类内部定义的方法,它是不可枚举的。这一点与 ES5 的行为不一致。

```javascript
var Point = function (x, y) {
// ...
};

Point.prototype.toString = function() {
Point.prototype.toString = function () {
// ...
};

Expand All @@ -162,11 +164,11 @@ Object.getOwnPropertyNames(Point.prototype)
// ["constructor","toString"]
```

上面代码采用 ES5 的写法,`toString`方法就是可枚举的。
上面代码采用 ES5 的写法,`toString()`方法就是可枚举的。

### constructor 方法

`constructor`方法是类的默认方法,通过`new`命令生成对象实例时,自动调用该方法。一个类必须有`constructor`方法,如果没有显式定义,一个空的`constructor`方法会被默认添加。
`constructor()`方法是类的默认方法,通过`new`命令生成对象实例时,自动调用该方法。一个类必须有`constructor()`方法,如果没有显式定义,一个空的`constructor()`方法会被默认添加。

```javascript
class Point {
Expand All @@ -178,9 +180,9 @@ class Point {
}
```

上面代码中,定义了一个空的类`Point`,JavaScript 引擎会自动为它添加一个空的`constructor`方法。
上面代码中,定义了一个空的类`Point`,JavaScript 引擎会自动为它添加一个空的`constructor()`方法。

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

```javascript
class Foo {
Expand All @@ -193,7 +195,7 @@ new Foo() instanceof Foo
// false
```

上面代码中,`constructor`函数返回一个全新的对象,结果导致实例对象不是`Foo`类的实例。
上面代码中,`constructor()`函数返回一个全新的对象,结果导致实例对象不是`Foo`类的实例。

类必须使用`new`调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用`new`也可以执行。

Expand Down Expand Up @@ -251,7 +253,7 @@ point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true
```

上面代码中,`x``y`都是实例对象`point`自身的属性(因为定义在`this`变量上),所以`hasOwnProperty`方法返回`true`,而`toString`是原型对象的属性(因为定义在`Point`类上),所以`hasOwnProperty`方法返回`false`。这些都与 ES5 的行为保持一致。
上面代码中,`x``y`都是实例对象`point`自身的属性(因为定义在`this`变量上),所以`hasOwnProperty()`方法返回`true`,而`toString()`是原型对象的属性(因为定义在`Point`类上),所以`hasOwnProperty()`方法返回`false`。这些都与 ES5 的行为保持一致。

与 ES5 一样,类的所有实例共享一个原型对象。

Expand Down Expand Up @@ -282,7 +284,7 @@ var p3 = new Point(4,2);
p3.printName() // "Oops"
```

上面代码在`p1`的原型上添加了一个`printName`方法,由于`p1`的原型就是`p2`的原型,因此`p2`也可以调用这个方法。而且,此后新建的实例`p3`也可以调用这个方法。这意味着,使用实例的`__proto__`属性改写原型,必须相当谨慎,不推荐使用,因为这会改变“类”的原始定义,影响到所有实例。
上面代码在`p1`的原型上添加了一个`printName()`方法,由于`p1`的原型就是`p2`的原型,因此`p2`也可以调用这个方法。而且,此后新建的实例`p3`也可以调用这个方法。这意味着,使用实例的`__proto__`属性改写原型,必须相当谨慎,不推荐使用,因为这会改变“类”的原始定义,影响到所有实例。

### 取值函数(getter)和存值函数(setter)

Expand Down

0 comments on commit 3459393

Please sign in to comment.