持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情
什么是 Class ?
在ES6中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类。
class 的本质是 function。
它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。
基础用法
function Person(name) {
this.name = name;
}
Person.prototype.say = function (msg) {
console.log(`${this.name} say ${msg}`);
};
var p = new Person('baicai');
p.say('hellow');
// baicai say hellow
使用 Class 之后
class Person {
constructor(name) {
this.name = name;
}
say(msg) {
console.log(`${this.name} say ${msg}`);
}
}
var p = new Person('baicai');
p.say('hello class');
// baicai say hello class
类的数据类型是函数,类本身就指向构造函数
typeof Person; // "function"
Person === Person.prototype.constructor; // true
类的实例的调用方法,其实就是调用原型上的方法
p.constructor === Person.prototype.constructor; // true
prototype 仍旧存在,虽然可以直接自类中定义方法,但是其实方法还是定义在 prototype 上的。因此可以使用 Object 的一些方法。
Object.assign() 覆盖方法 / 初始化时添加方法
Object.assign(Person.prototype, { sex: 'man' }, { age: '18' });
// {sex: 'man', age: '18', constructor: ƒ, say: ƒ}
类的内部所有定义的方法,都是不可枚举的( constructor / say)
Object.keys(Person.prototype); // ['sex', 'age']
Object.getOwnPropertyNames(Person.prototype); // ['constructor', 'say', 'sex', 'age']
注意
- 类名不能重复;
let Demo = class {};
class Demo {}
// Uncaught SyntaxError: Identifier 'Demo' has already been declared
- 类的定义不会提升, 必须先定义后使用。
类的实例
类的实例化必须通过 new 关键字。
class Person {}
let p = Person();
// Uncaught TypeError: Class constructor Person cannot be invoked without 'new'
类的所有实例共享一个原型对象
class Person {
constructor(name) {
this.name = name;
}
}
var p1 = new Person('xiaobai');
var p2 = new Person('xiaohei');
Object.getPrototypeOf(p1) == Object.getPrototypeOf(p2); // true
// 或者在浏览器中
p1.__proto__ === p2.__proto__; // true
类的主体
方法
constructor
类的默认方法,创建类的实例化对象时被调用,返回实例对象(即 this),也可以指定返回另外一个对象。
class Test {
constructor() {
// 默认返回实例对象 this
}
}
console.log(new Test() instanceof Test); // true
class Demo {
constructor() {
// 指定返回对象
return new Test();
}
}
console.log(new Demo() instanceof Demo); // false
静态方法
类通过 static 关键字定义静态方法,改该方法不会被实例继承,只能通过类来调用。
class Person {
constructor() {}
static firstName() {
return 'wu';
}
}
Person.firstName(); // 'wu'
var p = new Person();
p.firstName(); // Uncaught TypeError: p.firstName is not a function
静态方法调用同一个类中的其他静态方法,可使用 this 关键字。
class Person {
constructor() {}
static firstName() {
return 'wu';
}
static age() {
return 18;
}
static info() {
return `userInfo: name: ${this.firstName()}, age: ${this.age()}`;
}
}
class Child extends Person {
static parentAge() {
return super.age();
}
}
Person.info(); // 'userInfo: name: wu, age: 18'
// 父类的静态方法,可以被子类继承。
Child.info(); // 'userInfo: name: wu, age: 18'
// 静态方法也是可以从super对象上调用的。
Child.parentAge(); // 18
属性
静态属性
静态属性指的是 Class 本身的属性,即 Class.propName,而不是定义在实例对上的属性。
class Person {
static age = 18;
}
Person.sex = 'man';
name 属性
返回跟在 class 后的类名
class Person {}
Person.name; // 'Person'
实例属性
属性也可以定义在类的最顶层
class Person {
age = 18;
constructor() {
console.log(this.age);
}
}
new Person(); // console.log(this.age);
this 的使用
类的方法内部如果含有 this,它默认指向类的实例
class Person {
getName() {
console.log('this.firstName() :>> ', this.firstName());
}
firstName() {
return 'wu';
}
}
var p = new Person();
p.getName(); // this.firstName() :>> wu
当你想通过结构的方式使用的时候
var { getName } = p;
getName(); // Cannot read properties of undefined (reading 'firstName')
this 会指向该方法运行时所在的环境, 而 class 内部是严格模式,所以 this 实际指向的是 undefined ,从而导致找不到 firstName 方法而报错。
解决方案
使用 bind , 在构造方法中绑定 this
class Person {
constructor() {
this.getName = this.getName.bind(this);
}
getName() {
console.log('this.firstName() :>> ', this.firstName());
}
firstName() {
return 'wu';
}
}
var p = new Person();
var { getName } = p;
getName(); // VM698:6 this.firstName() :>> wu
使用箭头函数,箭头函数内部的 this 总是指向定义时所在的对象
class Person {
constructor() {
this.getName = () => console.log('this.firstName() :>> ', this.firstName());
}
// getName(){
// console.log('this.firstName() :>> ', this.firstName());
// }
firstName() {
return 'wu';
}
}
var p = new Person();
var { getName } = p;
getName(); // this.firstName() :>> wu