12. class (类)的用法

207 阅读3分钟

类的介绍

JavaScript 语言中,生成实例对象的传统方法是通过构造函数,上面这种写法跟传统的面向对象语言(比如 C++ 和 Java)差异很大,很容易让新学习这门语言的程序员感到困惑

//es5造类
function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype.sayName = function () {
    return this.name;
}
Person.prototype.sayAge = function () {
    return this.age;
}
let p1 = new Person('Max', 23);
console.log(p1); //Person {name: "Max", age: 23}
console.log(p1.sayName()); //Max
console.log(p1.sayAge()); //23

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类

基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用 ES6 的class改写,就是下面这样

//es6造类
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        return this.name;
    }
    sayAge() {
        return this.age;
    }
}
let p1 = new Person('Max', 23);
console.log(p1); //Person {name: "Max", age: 23}
console.log(p1.sayName()); //Max
console.log(p1.sayAge()); //23

//通过Object.assign()方法一次性向类中添加多个放大 - 只做了解
Object.assign(Person.prototype, {
    sayName(){
        return this.name;
    },
    sayAge(){
        return this.age;
    },
})

上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象

类的继承

使用关键字 extends 来让子类继承父类的方法,然后通过super调用父类中的constructor方法

class Animal {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        return this.name;
    }
    sayAge() {
        return this.age;
    }
}

class Dog extends Animal {
    constructor(name, age, kind) {
        super(name, age); //super是超类的意思,它会去调用父类中的contructor方法
        // Animal.call(this, mame, age);
        this.kind = kind;
    }
    //子类自己的方法
    sayInfo() {
        return `${this.name}已经${this.age}岁了,是条${this.kind}。`
    }
    //重写父类的方法 - 子类的方法与父类同名就会覆盖父类的方法
    sayName() {
        return this.name + this.sayAge() + this.kind;
    }
}

let dog1 = new Dog('小黄', 4, '秋田犬');
console.log(dog1.sayInfo());//小黄已经4岁了,是条秋田犬。
console.log(dog1.sayName());//小黄4秋田犬

Mixin 混入模式的实现*

摘自阮一峰 - ECMAScript 6 入门 - 只做了解

Mixin 指的是多个对象合成一个新的对象,新对象具有各个组成成员的接口

它的最简单实现如下,c对象是a对象和b对象的合成,具有两者的接口

const a = {
  a: 'a'
};
const b = {
  b: 'b'
};
const c = {...a, ...b};

下面是一个更完备的实现,将多个类的接口“混入”(mix in)另一个类

代码的mix函数,可以将多个对象合成为一个类,使用的时候,只要继承这个类即可

//声明mix函数,通过调用拷贝函数,来拷贝类的全部属性并返回,用剩余参数来接收不定个数的类来传参
function mix(...mixins) {
    class Mix {
        constructor() {
            for (let mixin of mixins) {
                copyProperties(this, new mixin()); // 拷贝实例属性
            }
        }
    }

    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);
        }
    }
}
//声明一个新的类,来继承并调用mix函数,传入需要混入的类,在mix函数中进行拷贝并接收返回的全部属性
class DistributedEdit extends mix(class1, class2, class3) {
    // ...
}

上面代码的mix函数,可以将多个对象合成为一个类。使用的时候,只要继承这个类即可