为什么会出现class

  • 它只是一个语法糖,会让面向对象的写法变得非常“舒服”

声明类的语法

class Person{ }
console.log(typeof Person); //function

const User = class { };
console.log(typeof User); //function
class Person{
  show() {
    console.log('hello world');
  }
}

const per = new Person();

per.show(); // hello world
// 函数书写形式
function Aniaml(name) {
  this.name = name;
}

const per = new Aniaml('wqt');
console.log(per.name); //wqt

// class的书写形式
class Animal{
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}

const per = new Animal('wqt');
console.log(per.getName()); //wqt

类的内部工作机制就是原型操作

  • 在类中声明的方法是挂载到类的原型上的
//以下两种写法等价
class User{
  show() {}
}

User.prototype.show = function () { }

对象属性的声明

class Person{
  sex = 'male'
  constructor(name) {
    this.name = name;
  }
  changeSex(newSex) {
    this.sex = newSex;
  }
  showSex() {
    console.log(this.sex);
  }
}

const per = new Person('王勤涛');

console.log(per); //Person { sex: 'male', name: '王勤涛' }

per.changeSex('female');

console.log(per.showSex()); //female

class声明的方法为什么不能被遍历

function User(name) {
  this.name = name;
}
User.prototype.show = function () { }
console.log(JSON.stringify(Object.getOwnPropertyDescriptor(User.prototype, 'show'))); //{"writable":true,"enumerable":true,"configurable":true}
const user = new User('wqt');

/**
 * name
 * show
 */
for (x in user) {
  console.log(x);
}

class Person{
  constructor(name) {
    this.name = name;
  }
  show() { }
}

console.log(JSON.stringify(Object.getOwnPropertyDescriptor(Person.prototype, 'show'))); //{"writable":true,"enumerable":false,"configurable":true}
const per = new Person('wqt');

/**
 * name
 */
for (x in per) {
  console.log(x);
}

严格模式下运行

class Person{
  show() {
    function test() {
      console.log(this);
    }
    test();
  }
}

const per = new Person();
per.show(); //undefined

静态属性的使用

//静态属性:构造函数写法
function Web(url) {
  this.url = url;
}

Web.url = 'http://www.baidu.com';

const web = new Web('houdunren.com');

console.log(web); //Web { url: 'houdunren.com' }
//静态属性
console.log(Web); //[Function: Web] { url: 'http://www.baidu.com' }

//静态属性:类的写法
class Person{
  static name = '王勤涛';
}

console.log(Person); //[class 王勤涛] { name: '王勤涛' }

静态方法的使用

//静态方法:构造函数实现
function User() { }
User.__proto__.info = function () {
  console.log('hello world');
}

User.info(); //hello world

class Person{
  static show() {
    console.log('hello world');
  }
}

Person.show(); //hello world

静态属性练习之模型管理类

const data = [
  { name: 'js', price: 100 },
  { name: 'mysql', price: 212 },
  { name: 'vue.js', price: 98 }
];

class Lesson{
  constructor(data) {
    this.model = data;
  }

  //将每一个课程抽象出一个对象
  static getAllLesson(data) {
    return data.map(lesson => new Lesson(lesson));
  }

  //统计最贵的课程
  static getMostExpensive(data) {
    data.sort((x, y) => {
      return y.price - x.price;
    });
    return data[0].name;
  }
}

/**
 * [
 *  Lesson { model: { name: 'js', price: 100 } },
 *  Lesson { model: { name: 'mysql', price: 212 } },
 *  Lesson { model: { name: 'vue.js', price: 98 } }
 * ]
 */
console.log(Lesson.getAllLesson(data));
console.log(Lesson.getMostExpensive(data)); //mysql

在类中使用访问器

class Request{
  constructor(url) {
    this._host = url;
  }
  set host(url) {
    if (!/^https?:\/\//.test(url)) {
      throw new Error('这个url不合法');
    }
    this._host = url;
  }
  get host() {
    return this._host;
  }
}

const req = new Request('http://www.baidu.com');
req.host = 'https://rocketturtlewqt.github.io';
console.log(req.host); //https://rocketturtlewqt.github.io

使用命名规则保护属性

class Request{
  //public
  _url = 'http://www.baidu.com';

  set url(url) {
    if (!/^https?:\/\//.test(url)) {
      throw new Error('url不合法');
    }
    this._url = url;
  }

  get url() {
    return this._url;
  }
}

const req = new Request();
req.url = 'https://rocketturtlewqt.github.io';
console.log(req.url); //https://rocketturtlewqt.github.io

使用symbel定义protected属性

const HOST = Symbol('url');

class Request{
  [HOST] = 'http://www.baidu.com';

  set url(url) {
    if (!/^https?:\/\//.test(url)) {
      throw new Error('url不合法');
    }
    this[HOST] = url;
  }

  get url() {
    return this[HOST];
  }
}

class Req extends Request{

}

const req = new Req();
req.url = 'https://rocketturtlewqt.github.io';
console.log(req.url); //https://rocketturtlewqt.github.io

private私有属性的使用

//私有:不能在外部及其子类中访问
class Person{
  //私有属性
  #host='https://rocketturtlewqt.github.io'
  constructor(name) {
    this.#check(name);
  }
  set host(url) {
    if (!/^https?:\/\//.test(url)) {
      throw new Error('url不合法')
    }
    this.#host = url;
  }
  //私有方法
  #check = (name) => {
    if (name.length < 5) {
      throw new Error('名字长度不能小于5';)
    }
    this.name = name;
  }
}

class属性继承原理

class Aniaml{
  constructor(name) {
    this.name = name;
  }
}

class Person extends Aniaml{
  constructor(name) {
    super(name);
  }
}

const per = new Person('王勤涛');
console.log(per);//Person { name: '王勤涛' }

类的方法继承原理

//函数实现继承
function Animal() { }
Animal.prototype.show = function () {
  console.log('show');
}

function Person() { }
Person.prototype = Object.create(Animal.prototype);

//类实现继承,与函数实现继承的原理相同
class Human{
  show() {
    console.log('show');
  }
}

class User extends Human{ }

为什么子类constructor中执行super

class Animal{
  constructor(name) {
    this.name = name;
    this.sex = 'female';
  }
}
//子类构造函数中必须要使用super,并且要放在最前面,因为子类构造函数的优先级要比父类高
class Person{
  constructor(name) {
    super(name);
    this.sex = 'male';
  }
}

静态继承原理

//静态方法继承原理
function Animal() { }
Animal.name = 'wqt';
Animal.show = function () {
  console.log('show');
}

function Person() { }
Person.__proto__ = Animal;
Person.show();// show

//实现的原理如上
class Admin{
  static name = 'wqt';
  static show() {
    console.log('show');
  }
}

class User extends Animal{ }
User.show();// show