简介
类(class)是es6中新增地基础性语法糖结构,提供了更加简洁、易读和易维护的语法。但他背后使用的仍热是原型和构造函数的概念,不可以被提升,受块级作用域影响。是一个函数
类的构成包含构造函数方法,实例方法,获取函数,设置函数和静态类方法
定义
- 类声明
- 类表达式
class Person { }
const Animal = class { }
构造函数constructor
constructor关键字用于在类定义块内部创建创建类的构造函数。在使用new操作符创建类的实例时会自动调用构造函数
使用new调用类的构造函数会执行如下操作
- 在内存中创建一个对象
- 这个新对象内部的[[ prototype ]]指针被赋值为构造函数的
prototype属性 - 构造函数内部的this指向新对象
- 执行构造函数内部的代码(给新对象添加属性)
- 如果构造函数返回非空的对象,则返回该对象;否则返回刚创建的新对象。
class Person {
// 添加到this的所有内容都会存在不同的实例中
constructor(name,age){
// ?? 空值合并操作符
this.name = name ?? null
this.age = age
}
// 在类块中定义的所有内容都会定义在类的原型上
sayName(){
console.log(this.name)
}
}
let p = new Person('张三',18)
console.log(Person.prototype)
console.log('p.prototype访问:',p.prototype)
console.log('Object.getPrototypeOf()访问:',Object.getPrototypeOf(p))
p.sayName()
console.log(typeof Person) // function
实例、原型和类成员
1、实例成员
每次通过new调用类标识符时,都会执行类构造函数,在这个函数中可以为新创建的实例添加“自由”属性。每个实例都对应一个唯一的成员对象,这意味着所有成员都不会在原型上共享
class Person {
constructor(age){
this.name = new String('张三')
this.friends = ['李四','王五']
}
sayName(){
console.log(this.name)
}
}
let p1 = new Person
let p2 = new Person
p1.sayName()
p2.sayName()
console.log(p1.name === p2.name) // false
console.log(p1.friends === p2.friends) // false
2、原型方法与访问器
为了在实例中共享方法,在类块中定义的方法作为原型方法
class Person{
constructor(){
this.locate = () => console.log('我在实例中')
}
locate(){
console.log('我在原型上')
}
}
let p = new Person()
p.locate()
Person.prototype.locate()
不能在类块中给原型添加原始值或对象作为成员数据,但可以在外面给类原型添加
class Person {
name : '张三'
}
class Person { }
Person.prototype.name = '张三'
console.log(Person.prototype)
类也支持获取和设置访问器
class Person {
constructor(){
this._name = '张三'
}
set name(newName){
this._name = newName
}
get name(){
return this._name
}
}
let p = new Person()
console.log(p._name) // 张三
p.name = '李四'
console.log(p._name) // 李四
静态类方法
静态方法常用于执行不特定于实例的操作,也不要求存在类的实例。与原型成员类似,每个类上只有一个静态成员,使用static关键字定义。在静态成员中,this引用类自身。只能通过类名调用静态方法
class MyClass {
static myStaticMethod() {
console.log("我是静态方法");
}
myInstanceMethod() {
MyClass.myStaticMethod(); // 通过类名调用静态方法
}
}
const myObj = new MyClass();
myObj.myStaticMethod()// TypeError: myObj.myStaticMethod is not a function
myObj.myInstanceMethod(); // "我是静态方法"
MyClass.myStaticMethod(); // 通过类名调用静态方法
继承
es6支持单继承,使用extends关键字,就可以继承任何拥有construct和原型的对象。这意味着不仅可以继承一个类,也可以继承普通的构造函数
class Vehicle(){
identifyPrototype(id){
console.log(id,this)
}
static identifyClass(id){
console.log(id,this)
}
}
class Bus extends Vehicle{ } // 继承类
let b = new Bus()
console.log(b instanceof Bus) // true
console.log(b instanceof Vehicle)// ture
// 类和原型的方法都会带到派生类。this的值反映调用相应方法的实例或类
let v = new Vehicle()
b.identifyPrototype('bus')// bus, Bus{}
v.identifyClass('Vehicle')// Vehicle, Vehicle{}
Bus.identifyClass('bus')// bus , class Bus {}
Vehicle.identifyClass('Vehicle') Vehicle, class Vehicle{}
function Person{ }
class Enginner extends Person { } // 继承普通构造函数
let e = new Enginner()
console.log(e instanceof Enginner) // true
console.log(e instanceof Person)// ture
构造函数 和 super()
派生类通过super关键字引用他们的原型,super只能在派生类中使用。而且仅限于构造函数,实例方法和静态方法内部
构造函数
class Person {
constructor(name){
this.name = name
}
sayName(){
console.log(this.name)
}
}
class Child extends Person {
constructor(name){
// 不能在调用 super()之前调用this,否则会抛出错误
super(name)
console.log(this instanceof Person)
console.log(this)
}
}
let c = new Child('张三')
c.sayName()
静态方法
class Person{
static sayHello(){
console.log('调用超类静态方法')
}
}
class Child extends Person {
static sayHello(){
super.sayHello()
}
}
Child.sayHello() // 调用超类静态方法
在使用super时注意的几个问题
- super只能在
派生类的构造函数和静态方法中使用,不能单独引用super - 调用
super会调用父类构造函数,并将实例赋值给this。可以传参 - 不能在调用super之前使用this
- 如果在派生类中显示的定义了构造函数,则必须要
调用super或者返回一个对象