ES5中继承的写法
- 构造函数继承可以继承属性
- 原型继承可以继承方法
组合起来就可以既可以继承属性又可以继承方法
通过构造函数模拟继承
// 父类
// 属性定义在构造函数中
function Animal(name){
// 实例属性(同实例化对象是有关系的)是定义在构造函数中的
this.name = name
}
// 方法定义在原型上
// 不管是静态属性/方法都是直接定义在类/构造函数上的
// 静态属性:如:Animal.count = 2
// 静态方法: 如:Animal.getCount = function(){}
// showName为实例方法,因为它的实例化对象可以获取到这个方法
Animal.prototype.showName = function(){
console.log('动物的名字是:' + this.name);
}
// 子类
function Dog(name,color){
// 实例属性是定义在类上的(同实例化对象是有关系的)
this.color = color
// 继承父类属性
Animal.call(this,name)
}
Dog.prototype = new Animal()
Dog.prototype.constructor = Dog
let d1 = new Dog('wangcai','black')
console.log(d1); // {color: 'black', name: 'wangcai'} 此处的name是继承自Animal的name
d1.showName() // 动物的名字是:wangcai
ES6中继承
ES6中继承的写法
ES6中的继承只是ES5中继承的『语法糖』,包括关键字:class、extends、constructor、static、super、get / set
// 父类
class People{
// 属性定义在constructor中
constructor(name,age){
this.name = name
this.age = age
}
// 方法直接定义在类的顶级作用域中
showName(){
console.log(this.name);
}
}
// 子类
class Coder extends People{
// name,age为父类中的属性,company为子类的属性
constructor(name,age,company){
// 通过super关键字继承父类的属性
super(name,age)
this.company = company
}
showCompany(){
console.log(this.company);
}
}
let c1 = new Coder('zhangsan',18,'Alibaba')
console.log(c1);
c1.showName()
c1.showCompany()
使用get和set关键字对设置属性和获取属性进行拦截
通过get和set关键字,把属性定义在类的最顶层
之前的实例实行都定义在constructor构造函数中
class People{
// 属性定义在constructor中
constructor(name,age){
this.name = name
this.age = age
}
get gender(){
return 'male'
}
set gender(val){
this.gender = val //报错: mximum call stack size exceeded
}
// 方法直接定义在类的顶级作用域中
showName(){
console.log(this.name);
}
}
// 子类
class Coder extends People{
// name,age为父类中的属性,company为子类的属性
constructor(name,age,company){
// 通过super关键字继承父类的属性
super(name,age)
this.company = company
}
showCompany(){
console.log(this.company);
}
}
let p1 = new People()
p1.gender = 'femail' // cannot set property gender of #<People> which has only a getter
console.log(p1.gender); //male
通过get关键字声明的属性表示这个属性是只读的,如果设置值会报错
如果想要赋值就要设置一个set方法.下面这种写法会及进入“死循环”
set gender(val){
this.gender = val //报错: mximum call stack size exceeded
}
因为只要设置值就会触发set方法,触发set方法就又会设置值,这样就进入死循环了
在set的时候我们不能直接给属性设置值,而是给一个"中间属性"设置值(_gender)
class People{
// 属性定义在constructor中
constructor(name,age){
this.name = name
this.age = age
this._gender = -1
}
get gender(){ // 属性
return this._gender
}
set gender(val){ // 属性
this._gender = val
}
// 方法直接定义在类的顶级作用域中
showName(){
console.log(this.name);
}
}
// 子类
class Coder extends People{
// name,age为父类中的属性,company为子类的属性
constructor(name,age,company){
// 通过super关键字继承父类的属性
super(name,age)
this.company = company
}
showCompany(){
console.log(this.company);
}
}
let p1 = new People()
p1.gender = 'femail'
console.log(p1.gender); //female
什么情况下使用get和set关键字?
那么使用关键字get 在类的最顶层声明的属性和constructor中声明的属性有什么区别吗?
放在constructor中的属性,当我们在取值和设置值得时候,要么是直接取,要么是直接设置,如果在取值和设置值的时候还有些业务逻辑的操作呢?在constructor中定义属性,就满足不了需求,而是应该通过get/set方法定义在类的顶层属性上,因为这样可以对属性的读写进行拦截的操作
比如: 在给gender设置值的时候,如果设置1就返回mail,如果设置1就返回femail
class People{
// 属性定义在constructor中
constructor(name,age){
this.name = name
this.age = age
this._gender = -1
}
get gender(){ // 属性
if(this._gender === 1){
return 'male'
}else if(this._gender === 0){
return 'female'
}else{
return 'Error: "传入非法的gender属性值"'
}
}
set gender(val){ // 属性
if(val === 0 || val === 1){
this._gender = val
}
}
// 方法直接定义在类的顶级作用域中
showName(){
console.log(this.name);
}
}
// 子类
class Coder extends People{
// name,age为父类中的属性,company为子类的属性
constructor(name,age,company){
// 通过super关键字继承父类的属性
super(name,age)
this.company = company
}
showCompany(){
console.log(this.company);
}
}
let p1 = new People()
// 设置属性值触发set
p1.gender = 1
// 获取属性触发get
console.log(p1.gender); // male
let c1 = new Coder('zhangsan',18,'Alibaba')
c1.gender = 0 // female
console.log(c1.gender);
static关键字定义静态方法
静态属性/方法: 直接定义在类上,不能被示例调用
ES6规定:class内部只有静态的方法,不支持静态属性,如果想添加就类名.属性 = 'xxx'
class People{
// 属性定义在constructor中
constructor(name,age){
this.name = name
this.age = age
this._gender = -1
}
get gender(){ // 属性
if(this._gender === 1){
return 'male'
}else if(this._gender === 0){
return 'female'
}else{
return 'Error: "传入非法的gender属性值"'
}
}
set gender(val){ // 属性
if(val === 0 || val === 1){
this._gender = val
}
}
// 方法直接定义在类的顶级作用域中
showName(){
console.log(this.name);
}
// 定义静态方法(不能被示例调用)
static getount(){
return 5
}
}
// 子类
class Coder extends People{
// name,age为父类中的属性,company为子类的属性
constructor(name,age,company){
// 通过super关键字继承父类的属性
super(name,age)
this.company = company
}
showCompany(){
console.log(this.company);
}
}
let p1 = new People()
// 设置属性值触发set
p1.gender = 1
// 获取属性触发get
console.log(p1.gender); // male
console.log(People.getount()); // 5
let c1 = new Coder('zhangsan',18,'Alibaba')
c1.gender = 0 // female
console.log(c1.gender);
console.log(Coder.getount()); // 5
注意:
class只是基于原型继承的语法糖,底层还是和ES5一样的:
console.log(typeof People); // function