文章目录
class类 与 构造函数
提示:以下是本篇文章正文内容,下面案例可供参考
class类
一、创建一个类
constructor
函数在创建实例化对象的时候,就进行调用
class Car {
// 构造器方法
constructor(name, price) {
// 构造器中的this--类的实例对象
this.name = name
this.price = price
},
// 一般方法
// 这个方法放在了类的原型对象上,供实例使用
// 通过Car的实例调用该方法时,this指向的就是Car的实例对象
drive() {
console.log(`我开${this.name}牌汽车`)
}
}
// 创建Car的实例对象
const c1 = new Car('奔驰', '50w')
const c2 = new Car('宝马', '40w')
- 通过赋值语句创建的方法,是放在实例自身上的,调用通过
实例对象名.方法名
- 直接声明的方法,是放在原型对象上的,调用通过
实例对象名.方法名
-
- 如果方法前面用
static
进行修饰,这个方法时放在类的本身上的,调用通过类名.方法名
- 如果方法前面用
class Car {
drive() {
console.log('这个方法放在了原型对象上')
}
fun = ()=> {
console.log('这个方法放在了实例自身上')
}
static fun1 = ()=> {
console.log('我前面用static进行修饰, 我是加在类本身的方法上的方法')
}
static fun2() {
console.log('我前面用static进行修饰, 我是加在类本身的方法上的方法')
}
}
const c1 = new Car()
c1.drive()
c1.fun()
Car.fun1()
Car.fun2()
二、继承
1 全部继承自父类
class Bus extends Car {}
const b1 = new Bus('解放', '10W')
console.log(b1)
// Bus { name: '解放', price: '10W' }
b1.drive()
// 我开解放牌汽车
2 super关键字
// 继续上面的例子
class Bus extends Car {
constructor(name, price, load) {
super(name, price)
this.load = load
}
}
const b1 = new Bus('解放', '10W', '20t')
console.log(b1)
// Bus { name: '解放', price: '10W', load: '20t' }
super
关键字只能放在构造器函数最前面执行
2.1 类中的继承关系
// 继续上面的例子
b1.drive()
// 我开解放牌汽车
此时,b1
的原型对象Bus上并没有drive
方法,因此通过原型链向上找到Car
原型对象,Car
的原型上有drive
,因此,此时b1
是通过原型链调用的Car
上的方法
class Bus extends Car {
constructor(name, price, load) {
super(name, price)
this.load = load
}
drive() {
console.log(`我开${this.name}牌汽车,我的载重是${this.load}`)
}
}
const b1 = new Bus('解放', '10W', '20t')
b1.drive()
// 我开解放牌汽车,我的载重是20t
此时,b1
的原型对象Bus上有drive
方法,因此,b1
调用的就是他原型对象上的drive
方法
2.2 super调用父类中的普通函数
class Car {
constructor(name, price) {
this.name = name
this.price = price
}
drive() {
return `我是${this.name}牌汽车,我的价格是${this.price}`
}
}
class Bus extends Car {
constructor(name, price, weight) {
super(name, price)
this.weight = weight
}
drive() {
console.log(super.drive() + ',我的载重是' + this.weight)
}
}
const b1 = new Bus('解放', '10w', '10t')
b1.drive()
在子类的普通函数中,可以通过super.父类函数名()
,来调用父类中的普通函数
构造函数和原型
1 创建一个构造函数
function Car(name, price) {
this.name = name
this.price = price
this.drive = ()=> {
console.log(`我是${this.name}牌汽车,我的价格是${this.price}`)
}
}
const c1 = new Car('奔驰', '50w')
console.log(c1)
c1.drive()
2 实例成员和静态成员
构造函数中的属性和方法,统称为成员。
- 实例成员就是在构造函数中,通过this添加的成员。实例成员只能通过实例对象进行方法,不能通过构造函数进行访问
- 静态资源是在构造函数本身添加的成员。静态资源只能通过构造函数访问,不能通过实例对象访问
function Car(name, price) {
this.name = name
this.price = price
this.drive = ()=> {
console.log(`我是${this.name}牌汽车,我的价格是${this.price}`)
}
}
Car.country = '美国'
const c1 = new Car('奔驰', '50w')
// name price drive都是实例成员,只能通过实例对象进行访问,不能通过构造函数进行访问
console.log(c1.price) // 50w
console.log(Car.price) // undefined
// length是在构造函数本身添加的成员,所以是静态成员
console.log(c1.country) // undefined
console.log(Car.country) // 美国
3 prototype原型对象
在创建构造函数时,我们不要把不变的方法定义到构造函数内部,这样浪费内存,要定义到构造函数prototype
原型对象上。
function Car(name, price) {
this.name = name
this.price = price
}
// 这里如果用箭头函数,会造成this为undifined
Car.prototype.drive = function() {
console.log(`我是${this.name}牌汽车,我的价格是${this.price}`)
}
const c1 = new Car('奔驰', '50w')
c1.drive()
- 原型是一个对象,我们也称为
prototype
原型对象 - 我们把方法定义到
prototype
原型对象上后,所有的实例都可以使用这个方法,不会在内存开辟新的空间 - prototype原型对象上有个属性constructor,他指向构造函数本身。
- prototype原型对象中的this指向的是实例对象
4 对象原型__proto__
对象上有一个属性__proto__
,他指向的是实例对象的构造函数的prototype
原型对象
- 实例对象的
__proto__
属性 等价于 构造函数的prototype
属性 - 调用时,首先看实例对象上是否有要调用的方法,如果没有,就去
__proto__
上查找对应方法,等于去构造函数的prototype
原型对象上查找。
5 原型链
c1
通过c1.__proto__
指向Car.prototype
,car的原型对象prototype也是一个对象,他也有__proto__
属性,Car.prototype.__proto__
指向的是Object.prototype
原型对象,Object.prototype.__proto__
指向null
6 继承
function Father (fullName, age) {
this.fullName = fullName
this.age = age
}
Father.prototype.say = function() {
console.log('我要说', this.fullName)
}
function Son (fullName, age, height) {
// 通过call方法,调用构造函数Father,并将他的this修改为Son
// 通过这种方法继承构造函数内部的属性和方法
Father.call(this, fullName, age)
this.height = height
}
// 通过这种方式继承挂载到原型对象上的属性和方法
Son.prototype = new Father()
// 再手动将constructor指向回Son
Son.prototype.constructor = Son
const s = new Son('小明', 18, '180')
console.log(s)
s.say()