Class
ES6 引入了 Class 这个概念,通过关键字 class
,可以定义类
关键字 class
可以看作是构造函数的语法糖,class
的绝大部分功能都能通过构造函数实现
ES5 的构造函数
// 通过构造函数设置实例属性
function Person(name) {
this.name = name;
};
// 为原型 Person.prototype 添加方法, 使得所有实例共享此方法
Person.prototype.showName = function () {
return `名字: ${this.name}`;
};
const person = new Person("superman");
console.log(person.showName());
我们也可以通过 Object.assign()
方法给 Person.prototype
添加方法 / 属性
// 使用 Object.assign() 为 Person.prototype 添加方法
Object.assign(Person.prototype, {
showName() {
return `名字: ${this.name}`;
},
});
Class 的使用
- 构造方法
constructor
相当于 ES5 的构造函数,可以在constructor
里面添加实例的属性 - 可以在
class
里面直接编写方法,相当于为原型Person.prototype
添加方法, 使得所有实例共享此方法
class Person {
// 构造方法 constructor, 只要执行 new Person(), 构造方法就会被调用
constructor(name) {
this.name = name;
console.log(`执行构造函数`);
}
// 普通方法, 相当于为原型 Person.prototype 添加方法, 使得所有实例共享此方法
showName() {
return `名字: ${this.name}`;
}
};
const person = new Person(`superman`, 18);
console.log(person.showName());
class 的表达式写法:
const Person = class { // 匿名类
constructor() {
this.name = `superman`;
}
showName() {
return `名字: ${this.name}`;
}
};
const person = new Person();
console.log(person.showName());
构造方法 constructor
- 通过
new
创建实例时,会自动调用类的构造方法constructor
- 一个类必须有构造方法
constructor
,如果没有显式定义,JS 会默认添加一个空的构造方法
class Fn {}
// 等同于
class Fn {
constructor() {}
}
关于构造方法的返回值
- 构造方法
constructor
默认返回当前实例this
- 开发者也可以手动
return
值:
如果返回 [引用类型数据],会覆盖默认返回值
如果返回 [基本类型数据],则仍然返回当前实例this
class Foo {
constructor() {
return { name: 'superman' }; // 返回一个对象
};
};
const foo = new Foo();
console.log(foo); // { name: 'superman' }
console.log(foo instanceof Foo); // false
注意事项:
- 类必须使用关键字
new
调用
class Foo {
constructor() {
return Object.create(null);
};
};
Foo(); // TypeError: Class constructor Foo cannot be invoked without 'new'
- 如果方法名要用变量,就要使用
[]
的表达式
let a = 'showName';
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
};
[a]() {
return `名字:${this.name}`;
};
};
console.log(typeof Person); // function
let per1 = new Person("superman", 18);
console.log(per1['showName']()); // 可通过 ['showName'] 调用
console.log(per1[a]()); // 也可以通过 [a] 调用
// console.log(per1.a()); // 不能通过 a 调用函数
既然 []
内可以用字符串,那当然可以使用字符串拼接啦:
console.log(per1['show' + 'Name']()); // superman
-
使用 ES5 的构造函数模拟类,会出现函数提升,因为构造函数本质上就是一个函数嘛
使用 ES6 的
class
类,不会出现函数提升
let person = new Person(); // ReferenceError: Cannot access 'Person' before initialization
class Person {
constructor() {
this.name = "superman";
};
};
let per1 = new Person();
console.log(per1); // Person {}
function Person() {};
getter & setter
get xxx()
:获取指定值时 自动调用set xxx(xx)
:修改指定值时 自动调用
class Person {
constructor(age) {
this._age = age; // 下划线开头的属性, 为私有属性, 不能直接获取 (这是一个约定)
}
// getter; getter 里面不要写其他语句, 会报错
get age() {
console.log('getter 已被调用');
return this._age;
}
// setter
set age(value) {
console.log('setter 已被调用');
this._age = value;
}
};
const person = new Person(18);
console.log(person.age); // getter 已被调用 18
person.age = 21; // setter 已被调用
console.log(person.age); // getter 已被调用 21
静态方法
- 静态方法:用关键字
static
修饰的方法。静态方法需要通过类名调用
class Person {
fun() {
console.log(this); // this 指向实例
}
static staticFun() {
console.log(this); // this 指向类
}
};
const person = new Person();
person.fun(); // 通过实例调用方法
Person.staticFun(); // 通过类名调用静态方法
类的继承
// 编写父类
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
showName() {
console.log('父类的 showName 方法');
return `名字: ${this.name}`;
}
showAge() {
console.log('父类的 showAge 方法');
return `年龄: ${this.age}`;
}
};
// 编写子类
class Student extends Person {
// 如果子类实例中没有独有的属性, 可以不用编写构造方法
constructor(name, skill, age) {
// 在子类的构造方法中, 必须先通过 super 调用父类的构造方法
super(name, age);
// 设置子类实例独有的属性
this.skill = skill;
}
// 重写父类的方法
showName() {
// 在子类的普通方法中, 可以通过 super 调用父类的方法
super.showName();
// 编写其他逻辑代码
console.log('子类的 showName 方法');
return `名字: ${this.name}`;
}
// 编写子类的方法
showSkill() {
return `技能: ${this.skill}`;
}
}
const stu = new Student("superman", "逃课", 18);
console.log(stu.name, stu.skill); // superman 逃课
console.log(stu.showSkill()); // 技能: 逃课
console.log(stu.showAge()); // 父类的 showAge 方法 年龄: 18
console.log(stu.showName()); // 父类的 showName 方法 子类的 showName 方法 名字: superman