ES6 class 类

1、定义 “类”

之前都是使用new function来定义一个函数的类型,现在我们可以使用class关键字来定义一个函数类

1.1 普通函数定义的类

function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}
People.prototype.play = function () {
    console.log(`我是${this.name},今年${this.age}岁,我喜欢打游戏`)
}
People.prototype.sing = function () {
    console.log(`${this.name}还喜欢唱个歌`)
}
var zhangSan = new People("张三", 25, "男")
zhangSan.play();
zhangSan.sing();

1.2 class定义的类

class People {
    constructor(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    play() {
        console.log(`我是${this.name}今年${this.age}岁,我喜欢打游戏`)
    }
    sing() {
        console.log(`${this.name}还喜欢唱歌`)
    }
}
var lisi = new People("李四", 23, "女");
lisi.play();
lisi.sing();

虽然es6增加了class关键字,但是JavaScript中还是没有类的概念!依然是基于面向对象,而不是真正的面向对象,基于原型链来模型实现class,机理和普通函数定义的类是一样的

console.log(xiaohong.singsong === People.prototype.singsong) // true
console.log(xiaohong.hasOwnProperty("singsong")) // false
console.log(xiaohong.hasOwnProperty("name")) // true

 2、继承

2.1普通函数的继承

function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}
People.prototype.play = function () {
    console.log(`我是${this.name},今年${this.age}岁了,我喜欢打游戏`);
}
People.prototype.sing = function () {
    console.log("我花喜欢唱歌");
}

function Student(name, age, sex, id, score, school) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.id = id;
    this.score = score;
    this.school = school;
}
Student.prototype = new People();

Student.prototype.study = function () {
    console.log(`我的学校是${this.school},学号${this.id},成绩${this.score}`);
}
var xiaoming = new Student("小明", 22, "男", "100001", "90", "实验中学");
xiaoming.play();
xiaoming.study();

2.2继承的原理

2.3ES6实现继承

class People {
    constructor(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    play() {
        console.log(`我是${this.name}今年${this.age}岁,我喜欢打游戏`)
    }
    sing() {
        console.log(`${this.name}还喜欢唱歌`)
    }
}
class Student extends People {
    constructor(name, age, sex, id, score, school) {
        super(name, age, sex);
        this.id = id;
        this.score = score;
        this.school = school;
    }
    study() {
        console.log(`我的学校是${this.school},学号${this.id},成绩${this.score}`);
    }
}
var xiaoming = new Student("小明", 30, "男", 10001, 89, "实验中学")
xiaoming.play();
xiaoming.study();

3、constructor方法

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

class定义的构造函数,必须使用new关键字调用,否则会报错

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

Foo()

4、class类定义的构造函数没有变量声明的提升

4.1 普通函数创建构造函数,执行

var xiaoming = new People("小明",19,"男")
console.log(xiaoming);

function People(name,age,sex){
  this.name = name;
  this.age = age;
  this.sex = sex;
}

4.2 class定义的构造函数

var xiaohong = new People("小红",18,"女")
console.log(xiahong);

class People{
  constructor(name,age,sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
  }
}

5、继承的构造函数必须要在constructor中调用super否则会报错

class Point { /* ... */ }

class ColorPoint extends Point {
  constructor() {
   //内部没有调用super
  }
}
let cp = new ColorPoint();

继承的子类可以不用写constructor,但是不代表没有定义,系统会自动悄悄的给你加上下面的代码

constructor(...args) {
  super(...args);
}

继承的子类使用this之前必须要先调用super后再定义

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class ColorPoint extends Point {
  constructor(x, y, color,name) {
    this.name = name; // 报错
    super(x, y);
    this.color = color; // 正确
  }
}
    
var aa = new ColorPoint();
console.log(aa)

6、Object.getPrototypeOf方法

Object.getPrototypeOf()方法用来查询当前的子类的父亲

class People {
    constructor(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    play() {
        console.log(`我是${this.name}今年${this.age}岁,我喜欢打游戏`)
    }
    sing() {
        console.log(`${this.name}还喜欢唱歌`)
    }
}
class Student extends People {
    constructor(name, age, sex, id, score, school) {
        super(name, age, sex);
        this.id = id;
        this.score = score;
        this.school = school;
    }
    study() {
        console.log(`我的学校是${this.school},学号${this.id},成绩${this.score}`);
    }
}
var xiaoming = new Student("小明", 30, "男", 10001, 89, "实验中学")
xiaoming.play();
xiaoming.study();
console.log(Object.getPrototypeOf(Student) === People);
console.log(Object.getPrototypeOf(Student));

7、super关键字

super这个关键字,既可以当作函数使用,也可以当作对象使用

super 当函数使用

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

class A {
    constructor() {
        console.log("我是A的constructor")
    }
}
class B extends A {
    constructor() {
        super();
    }
}
var b = new B()

上面代码中,子类B的构造函数之中的super(),代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错。

虽然super当做函数调用的时候,调用的是父函数的constructor构造器,但是上下文还是子类的自己的上下文

new.target

class A {
  constructor() {
console.log(new.target);
console.log(new.target.name) // A
  }
}
new A() 

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

上面代码中,new.target指向当前正在执行的函数。可以看到,在super()执行时,它指向的是子类B的构造函数,而不是父类A的构造函数。也就是说,super()内部的this指向的是B

作为函数时,super()只能用在子类的constructor 构造函数之中,用在其他地方就会报错。

class A {}

class B extends A {
  m() {
    super(); // 报错
  }
}

super 当对象使用

super方法作为对象的时候,指向父类的原型对象

class A {
  p() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2
  }
}

let b = new B();

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

8、函数的get和set关键字

与ES5一样,在Class内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为

class MyClass {
    constructor() {
        // ...
    }
    get prop() {
        return 'getter';
    }
    set prop(value) {
        console.log('setter: '+value);
    }
}
let inst = new MyClass();
inst.prop = 666;
console.log(inst.prop)

9、静态方法 static

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”

静态化之前的 构造函数

class Foo {
    classMethod() {
        console.log("静态函数");
        
        return 'hello';
    }
}
console.log(Foo.classMethod) //undefined  必须通过  new

加了static关键字后

class Foo {
    static classMethod() {
        return 'hello';
    }
}
console.log(Foo.classMethod) // 返回classMethod函数体
console.log(Foo.classMethod() )// 'hello'

此时如果使用new产生实例后

var foo = new Foo();
foo.classMethod()

10、new.target属性

ES6为new命令引入了

function Person(name) {
    if (new.target !== undefined) {
        this.name = name;
    } else {
        throw new Error('必须使用new生成实例');
    }
}
var xiaohong =  new Person("小红")
console.log(xiaohong); // 小红
Person("xiaoming")//报错

一个new.target属性,(在构造函数中)返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的

11、混入Mixin

Mixin模式指的是,将多个类的接口“混入”(mix in)另一个类。它在ES6的实现如下。

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);
    }
  }
}

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

        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 Foo1{
            fun1(){
                console.log("fun1")
            }
        }
        class Foo2{
            fun2(){
                console.log("fun2")
            }
        }
        class Foo3{
            fun3(){
                console.log("foo3")
            }
        }
        class DistributedEdit extends mix(Foo1, Foo2,Foo3) {
            
        }
        new DistributedEdit().fun1();
        new DistributedEdit().fun2();
        new DistributedEdit().fun3();

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值