ES6中的class关键字

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

1 ES5 中的面向对象

// 创建一个构造函数
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)

2 ES6 中的 class 关键字

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

class People {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    say() {
       return 'hello everyone' 
    }
}

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

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

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

2.1 类的实例

同样的,也是用new 关键字

class People {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    say() {
       return 'hello everyone' 
    }
}
var people = new People('zhangsan', 18)

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

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

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__属性为“类”添加方法

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'

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

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

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 完全一致

2.3 一些需要注意的点

2.3.1 不存在变量提升

类不存在变量提升

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

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

2.3.2 name

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

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

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

2.3.3 Generator 方法

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

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

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循环会自动调用这个遍历器,不断返回多次,一次打印出一个参数,直到遍历出所有的参数

2.3.4 this

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

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

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'

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

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'

2.4 静态方法

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

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指的是类,而不是实例

class People {
    static hello() {
        this.say()
    }
    static say() {
        console.log('我是静态')
    }
    say() {
        console.log('我是非静态')
    }
}
People.hello() // 我是静态

2.5 静态属性

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

class Foo {
  static prop = 1;
}

2.6 私有方法

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

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

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

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

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

class People {
    // 公有方法
    foo (name) {
        getName.call(this, name)  
    }
}
// 私有方法
getName(name) {
    return this.peop = name
}

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

2.7 私有属性

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

2.8 类的继承

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

2.8.1 extends
// 这是父类
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) // 张三
2.8.2 super

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

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

// 这是父类
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作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类

// 这是父类
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()

3 参考文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值