ES6中的class关键字

ES6中的class关键字

欢迎访问我的博客,祝码农同胞们早日走上人生巅峰,迎娶白富美~~~

声明:本文参考业界大佬阮一峰老师的ES6标准入门

ES5 中的面向对象

1
2
3
4
5
6
7
8
9
10
11
12
13
// 创建一个构造函数
function People (name, age) {
this.name = name
this.age = age
}

// 向构造函数的原型对象中添加 say 方法
People.prototype.say = function () {
return 'hello everyone'
}

// 实例化 People 构造函数,并保存在变量 a 中
var a = new People('zhangsan', 10)

ES6 中的 class 关键字

ES6 中的 class 类去改写上面的例子看看

1
2
3
4
5
6
7
8
9
class People {
constructor(name, age) {
this.name = name
this.age = age
}
say() {
return 'hello everyone'
}
}

两个例子可以说实际功能一模一样,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象,且方法之间不需要逗号分隔,加了会报错

ES6class 类,完全可以看作构造函数的另一种写法,证明如下:

1
2
3
class People {  }
typeof People // "function"
People.prototype.constructor === People // true

类的实例

同样的,也是用new 关键字

1
2
3
4
5
6
7
8
9
10
class People {
constructor(name, age) {
this.name = name
this.age = age
}
say() {
return 'hello everyone'
}
}
var people = new People('zhangsan', 18)

ES5 一样,实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)

类的所有实例共享一个原型对象

1
2
3
4
5
6
7
8
9
10
11
12
class People {
constructor(name, age) {
this.name = name
this.age = age
}
say() {
return 'hello everyone'
}
}
var people1 = new People('zhangsan', 18)
var people2 = new People('zhaosi', 20)
people1._proto_ === people2._proto // true

这就意味着可以通过实例的__proto__属性为“类”添加方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class People {
constructor(name, age) {
this.name = name
this.age = age
}
say() {
return 'hello everyone'
}
}
var people1 = new People('zhangsan', 18)
var people2 = new People('zhaosi', 20)
people1._proto_.eat = function () {
return 'banner'
}
people1.eat() // 'banner'
people2.eat() // 'banner'

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

案例借用阮一峰老师的《ES6标准入门》

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CustomHTMLElement {
constructor(element) {
this.element = element;
}

get html() {
return this.element.innerHTML;
}

set html(value) {
this.element.innerHTML = value;
}
}

var descriptor = Object.getOwnPropertyDescriptor(
CustomHTMLElement.prototype, "html"
);

"get" in descriptor // true
"set" in descriptor // true

存值函数和取值函数是定义在html属性的描述对象上面,这与 ES5 完全一致

一些需要注意的点

不存在变量提升

类不存在变量提升

1
2
new Foo(); // ReferenceError
class Foo {}

如上代码,定义Foo在后,使用在前,则报错

name

由于本质上,ES6 的类只是ES5 的构造函数的一层包装,所以函数的许多特性都被Class继承,包括name属性

1
2
class People {}
People.name // "People"

name属性总是返回紧跟在class关键字后面的类名

Generator 方法

如果某个方法之前加上星号(*),就表示该方法是一个 Generator 函数

generator可以在执行过程中多次返回,所以它看上去就像一个可以记住执行状态的函数,利用这一点,写一个generator就可以实现需要用面向对象才能实现的功能,详细请移步廖雪峰老师的generator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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类的默认遍历器,for...of循环会自动调用这个遍历器,不断返回多次,一次打印出一个参数,直到遍历出所有的参数

this

类的方法内部如果含有this,它默认指向类的实例。但是,必须非常小心,一旦单独使用该方法,很可能报错

1
2
3
4
5
6
7
8
9
10
11
class People {
getPeople(name = 'zhangsan') {
this.print(`hello ${ name }`)
}
print(text) {
console.log(text)
}
}
const people = new People()
const { getPeople } = people
getPeople() // TypeError: Cannot read property 'print' of undefined

解决办法一:在constructor中绑定this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class People {
constructor() {
this.getPeople = this.getPeople.bind(this)
}
getPeople(name = 'zhangsan') {
this.print(`hello ${ name }`)
}
print(text) {
console.log(text)
}
}
const people = new People()
const { getPeople } = people
getPeople() // 'hello zhangsan'

解决方法二:使用箭头函数

1
2
3
4
5
6
7
8
9
10
11
class People {
constructor() {
this.getPeople = (name = 'zhangsan') => this.print(`hello ${ name }`)
}
print(text) {
console.log(text)
}
}
const people = new People()
const { getPeople } = people
getPeople() // 'hello zhangsan'

静态方法

static关键字,带有static关键字的方法不会被继承,且实例不能调用,必须用过类直接调用

1
2
3
4
5
6
7
8
9
10
11
12
class People {
constructor(name, age) {
this.name = name
this.age = age
}
static say() {
console.log('say everyone')
}
}
People.say() // 'hello everyone'
var people = new People
people.say() // TypeError: people.say is not a function

注意,如果静态方法包含this关键字,这个this指的是类,而不是实例

1
2
3
4
5
6
7
8
9
10
11
12
class People {
static hello() {
this.say()
}
static say() {
console.log('我是静态')
}
say() {
console.log('我是非静态')
}
}
People.hello() // 我是静态

静态属性

static关键字,加在属性前面,即定义了静态属性

1
2
3
class Foo {
static prop = 1;
}

私有方法

私有方法是常见需求,但 ES6不提供,只能通过变通方法模拟实现

方法一:在命名上加以区别

1
2
3
4
5
6
7
8
9
10
11
class People {
// 公有方法
foo (name) {
this._getName(name)
}

// 私有方法
_getName(name) {
return this.peop = name
}
}

上面代码中,getName方法前面的下划线,表示这是一个只限于内部使用的私有方法。但是,这种命名是不保险的,在类的外部,还是可以调用到这个方法

方法二:将私有方法移出模块

1
2
3
4
5
6
7
8
9
10
class People {
// 公有方法
foo (name) {
getName.call(this, name)
}
}
// 私有方法
getName(name) {
return this.peop = name
}

上述代码中,利用call使thisfoo调用了getName方法,这使得getName实际上成为了当前模块的私有方法

方法三:Symbol 值的唯一性

对于 Symbol 可以参考ES6中的Symbol

1
2
3
4
5
6
7
8
9
10
11
12
13
const a = Symbol('a')
const b = Symbol('b')
export default class People {
// 公有方法
foo (name) {
this[a](name)
}

// 私有方法
[a](name) {
return this[b] = name
}
}

私有属性

请参照http://es6.ruanyifeng.com/#docs/class

类的继承

Class 可以通过extends关键字实现继承,先看个例子

extends

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 这是父类
class Person {
constructor(name, age){
this.name = name
this.age = age
}
}

// 这是子类 美国人 可继承父类的一些属性和方法
class American extends Person {
}
const a1 = new American('Jack', 20)
console.log(a1.name) // Jack

// 这是子类 中国人 可继承父类的一些属性和方法
class Chinese extends Person{
}

const c1 = new Chinese('张三', 22)
console.log(c1.name) // 张三

super

既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同

情况一:super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 这是父类
class Person {
constructor(name, age){
this.name = name
this.age = age
}

// 打招呼 的 实例方法
sayHello(){
console.log('大家好')
}
}

// 这是子类 美国人
class American extends Person {
constructor(name, age){
super(name, age)
}
}

const a1 = new American('Jack', 20)
console.log(a1)
a1.sayHello()


// 这是子类 中国人
class Chinese extends Person{
// name 姓名
// age 年龄
// IDNumber 身份证号 【中国人独有的】,既然是独有的,就不适合 挂载到 父类上;
constructor(name, age, IDNumber){
super(name, age)
this.IDNumber = IDNumber
}
}

const c1 = new Chinese('张三', 22, '130428******')
console.log(c1)
c1.sayHello()

注意

  1. 如果需要添加自己独有的属性,则不能挂在到父类上
  2. 在子类中, this 只能放到 super 之后使用

情况二:super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 这是父类
class Person {
constructor(name, age){
this.name = name
this.age = age
}

// 打招呼 的 实例方法
sayHello(){
console.log('大家好')
}
}

// 这是子类 美国人
class American extends Person {
constructor(name, age){
super(name, age)
console.log(super.sayHello())
}
}

let amer = new American()

上面代码中,子类American当中的super.sayHello(),就是将super当作一个对象使用。这时,super在普通方法之中,指向Person.prototype,所以super.sayHello()就相当于Person.prototype.sayHello()

本文标题:ES6中的class关键字

文章作者:王工头

发布时间:2019年01月29日 - 23:54:37

最后更新:2019年01月30日 - 18:19:29

原始链接:https://qqqww.com/ES6中的class关键字/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------本文结束感谢大佬们的阅读-------------