提示:
本文为JavaScript栏目:JavaScript高级系列——ES6新特性章节 第十章
JavaScript高级学习:ES6新特性10——继承的学习01
前言
本文粗浅学习继承。
提示:以下是本篇文章正文内容,下面案例可供参考
继承
ES5与ES6中继承用法的对比
ES5中继承的用法
ES5中的继承实际上是通过代码的灵活运用,让s去自动同步了F的代码,写法是多种不固定的。
function F() {
this.color="red";
this.name="dog";
}
F.prototype.age=10;
function S() {
/*构造函数的继承*/
this.name=20; //语句1
F.call(this);
this.x=10;
}
/*原型继承*/
for(let k in F.prototype){
S.prototype[k]=F.prototype[k];
}
ES5中同名属性在父类构造调用前先赋值,会被F.call给覆盖,造成赋值无效 ,如语句1
ES5中的继承只能继承自定义的构造函数,内置的构造函数是无法继承。比如(Math,Date);
ES6中继承的用法
class A{
constructor(sex) {
this.name="张三";
this.sex=sex;
console.log(this); //A还是B
}
age=22;
}
class B extends A{
constructor(){
super("boy");
this.x=10;
}
show(){
}
}
let b=new B();
console.log(b.name); //张三
console.log(b.age); //22
console.log(b.sex); //boy
console.log(b.x); //10
解析:
父类A:
class A{
constructor(sex) {
this.name="张三";
this.sex=sex;
console.log(this); //A还是B
}
age=22;
}
/*在ES6中class可以通过extents关键字来实现类的继承
* class B extends A 表示A为父类,B为子类
* 这个时候子类(B类)可以使用A类中所有的非私有属性和方法*/
class B extends A{
/*子类中可以不写构造函数,代码在运行时会自动加上构造函数和super(),如果自己写了构造函数,就一定要记得调用super()*/
constructor(){
// this.x=5;
/*父级构造函数需要传参,子类调用父类构造函数时,可以传参,也可以不传参,这一点和java是不一样的,我们推荐传参使用*/
super("boy"); //调用父级的构造函数,子类中必读调用父类构造函数!!!!
/*this关键字必须在super之后使用*/
this.x=10;
}
show(){
/*super()表示的是父类构造函数的调用,只能写在子类的构造函数中。*/
/*普通方法不能使用super()函数,但是可以使用super关键字表示super对象*/
// super();
}
}
// let a=new A();
let b=new B();
console.log(b.name); //张三
console.log(b.age); //22
console.log(b.sex); //boy
console.log(b.x); //10
class A{
constructor(sex) {
this.name="张三";
this.sex=sex;
console.log(this); //A还是B
}
age=22;
}
/*在ES6中class可以通过extents关键字来实现类的继承
* class B extends A 表示A为父类,B为子类
* 这个时候子类(B类)可以使用A类中所有的非私有属性和方法*/
class B extends A{
/*子类中可以不写构造函数,代码在运行时会自动加上构造函数和super(),如果自己写了构造函数,就一定要记得调用super()*/
constructor(){
// this.x=5;
/*父级构造函数需要传参,子类调用父类构造函数时,可以传参,也可以不传参,这一点和java是不一样的,我们推荐传参使用*/
super("boy"); //调用父级的构造函数,子类中必读调用父类构造函数!!!!
/*this关键字必须在super之后使用*/
this.x=10;
}
show(){
/*super()表示的是父类构造函数的调用,只能写在子类的构造函数中。*/
/*普通方法不能使用super()函数,但是可以使用super关键字表示super对象*/
// super();
}
}
// let a=new A();
let b=new B();
console.log(b.name); //张三
console.log(b.age); //22
console.log(b.sex); //boy
console.log(b.x); //10
class A{
constructor(sex) {
this.name="张三";
this.sex=sex;
console.log(this); //A还是B
}
age=22;
}
/*在ES6中class可以通过extents关键字来实现类的继承
* class B extends A 表示A为父类,B为子类
* 这个时候子类(B类)可以使用A类中所有的非私有属性和方法*/
class B extends A{
/*子类中可以不写构造函数,代码在运行时会自动加上构造函数和super(),如果自己写了构造函数,就一定要记得调用super()*/
constructor(){
// this.x=5;
/*父级构造函数需要传参,子类调用父类构造函数时,可以传参,也可以不传参,这一点和java是不一样的,我们推荐传参使用*/
super("boy"); //调用父级的构造函数,子类中必读调用父类构造函数!!!!
/*this关键字必须在super之后使用*/
this.x=10;
}
show(){
/*super()表示的是父类构造函数的调用,只能写在子类的构造函数中。*/
/*普通方法不能使用super()函数,但是可以使用super关键字表示super对象*/
// super();
}
}
// let a=new A();
let b=new B();
console.log(b.name); //张三
console.log(b.age); //22
console.log(b.sex); //boy
console.log(b.x); //10
class A{
constructor(sex) {
this.name="张三";
this.sex=sex;
console.log(this); //A还是B
}
age=22;
}
/*在ES6中class可以通过extents关键字来实现类的继承
* class B extends A 表示A为父类,B为子类
* 这个时候子类(B类)可以使用A类中所有的非私有属性和方法*/
class B extends A{
/*子类中可以不写构造函数,代码在运行时会自动加上构造函数和super(),如果自己写了构造函数,就一定要记得调用super()*/
constructor(){
// this.x=5;
/*父级构造函数需要传参,子类调用父类构造函数时,可以传参,也可以不传参,这一点和java是不一样的,我们推荐传参使用*/
super("boy"); //调用父级的构造函数,子类中必读调用父类构造函数!!!!
/*this关键字必须在super之后使用*/
this.x=10;
}
show(){
/*super()表示的是父类构造函数的调用,只能写在子类的构造函数中。*/
/*普通方法不能使用super()函数,但是可以使用super关键字表示super对象*/
// super();
}
}
// let a=new A();
let b=new B();
console.log(b.name); //张三
console.log(b.age); //22
console.log(b.sex); //boy
console.log(b.x); //10
class A{
constructor(sex) {
this.name="张三";
this.sex=sex;
console.log(this); //A还是B
}
age=22;
}
/*在ES6中class可以通过extents关键字来实现类的继承
* class B extends A 表示A为父类,B为子类
* 这个时候子类(B类)可以使用A类中所有的非私有属性和方法*/
class B extends A{
/*子类中可以不写构造函数,代码在运行时会自动加上构造函数和super(),如果自己写了构造函数,就一定要记得调用super()*/
constructor(){
// this.x=5;
/*父级构造函数需要传参,子类调用父类构造函数时,可以传参,也可以不传参,这一点和java是不一样的,我们推荐传参使用*/
super("boy"); //调用父级的构造函数,子类中必读调用父类构造函数!!!!
/*this关键字必须在super之后使用*/
this.x=10;
}
show(){
/*super()表示的是父类构造函数的调用,只能写在子类的构造函数中。*/
/*普通方法不能使用super()函数,但是可以使用super关键字表示super对象*/
// super();
}
}
// let a=new A();
let b=new B();
console.log(b.name); //张三
console.log(b.age); //22
console.log(b.sex); //boy
console.log(b.x); //10
父类
class A{
constructor(sex) {
this.name="张三";
this.sex=sex;
console.log(this); //A还是B的问题
//let a=new A(); 输出为A {age: 22, name: "张三", sex: undefined}
//let b=new B(); 输出为B {age: 22, name: "张三", sex: "boy"}
}
age=22;
}
在ES6中class可以通过extents关键字来实现类的继承
class B extends A 表示A为父类,B为子类。这个时候子类(B类)可以使用A类中所有的非私有属性和方法
class B extends A{
constructor(){
super("boy");//语句2
this.x=10; //语句3
}
show(){
}
}
let b=new B();
子类中可以不写构造函数,代码在运行时会自动加上构造函数和super(),如果自己写了构造函数,就一定要记得调用super(),比如语句2。
父级构造函数需要传参,子类调用父类构造函数时,可以传参,也可以不传参,这一点和java是不一样的,我们推荐传参使用。但是调用父级的构造函数,子类中必读调用父类构造函数!!!!如语句2
this关键字必须在super之后使用,比如语句3
super()表示的是父类构造函数的调用,只能写在子类的构造函数中。普通方法不能使用super()函数,但是可以使用super关键字表示super对象,如:
class B extends A{
constructor(){
super("boy");
this.x=10;
}
show(){
super();
}
}
let b=new B();
console.log(b.name); //张三
console.log(b.age); //22
console.log(b.sex); //boy
console.log(b.x); //10
super关键字的使用
super关键字作为对象使用
class A{
constructor() {
this.name="张三";
this.show=function () {
console.log("A的构造函数中的方法");
}
}
age=18;
play() {
console.log(this);
console.log(this.abc);
console.log("A的构造函数中的原型方法");
}
}
A.prototype.sex="男";
let a =new A();
console.log(a.play());
class B extends A{
constructor() {
super();
this.abc="abc";
super.def="def";
console.log(super.def);
console.log(super.name);
console.log(super.age);
console.log(super.sex);
super.play();
}
}
let b=new B();
console.log(b);
let aa=new A();
console.log(aa);
解析
父类A
class A{
constructor() {
this.name="张三";
this.show=function () {
console.log("A的构造函数中的方法");
}
}
age=18; //不使用constructor函数直接写的属性也属于实例属性,但是要求必须在类的最顶层
play() {
console.log(this);
console.log("A的构造函数中的原型方法");
}
}
A.prototype.sex="男";
let a =new A();
console.log(a.play());
/*
A
A的构造函数中的原型方法
*/
子类B
子类中的super和父类中的this是等价的,如语句4
class A{
play() {
console.log(this);
console.log(this.abc); //子类中有abc属性,此时只有在子类中通过super关键字调用的play函数可以读取abc的值
console.log("A的构造函数中的原型方法");
}
}
let a =new A();
console.log(a.play());
/*
A
undefined
A的构造函数中的原型方法
*/
class B extends A{
constructor() {
super();// 在子类的构造函数中调用了父类的构造函数
this.abc="abc";
super.def="def";//语句4
console.log(super.def); // undefined
/*super对象只能获取父类的原型属性和原型方法*/
console.log(super.name); //undefined
console.log(super.age); //undefined
console.log(super.sex); //男
// super.show(); //报错
//play是A的原型方法,可以通过super调用
super.play();
}
}
let b=new B();
console.log(b); //B
let aa=new A();
console.log(aa); //A
概念1:super关键字在非静态函数中,super的指向是父类的原型对象。
概念2:子类的非静态函数通过super调用父类方法时,这个方法中的this指向子类的实例对象。
概念3:所以在这种情况下,super和this在赋值的时候是等价的。
super关键字在静态方法中的含义
创建一个父类
class F{
static name="爹";
static show(){
console.log(this);
console.log(this.name);
console.log("父级的静态函数");
}
show(){
console.log("父级的普通函数");
}
}
创建一个子类
super关键字在使用的时候必须显式的指定他是函数还是对象,要么super后面带括号,要么要使用‘.’运算符,如语句123。
子类的静态方法中通过super调用父类方法,调用到的是父类的静态方法,但是这个情况下,父类的静态方法中的this表示的是子类,而不是子类对象。
class S extends F{
static name="儿子";
static print(){
// console.log(super); //报错 //语句1
console.log(super.toString()); //语句2
console.log(super.valueOf()); //语句3
super.show(); //子类的静态方法中super关键字表示父类(F)
}
print(){
super.show(); //子类的普通方法中super关键字表示父类的原型对象
}
}
S.print();//通过类名调用静态方法
let s = new S();
s.print();//调用实例方法
S.print();//通过类名调用静态方法
/*
class S extends F{
static name="儿子";
static print(){
/*super关键字在使用的时候必须显式的指定他是函数还是对象,要么super后面带括号,要么要使用.运算符*/
// console.log(super); //报错
console.log(super.toString());
console.log(super.valueOf());
/*子类的静态方法中通过super调用父类方法,调用到的是父类的静态方法,但是这个情况下,父类的静态方法中的this表示的是子类,而不是子类对象*/
super.show(); //子类的静态方法中super关键字表示父类(F)
}
print(){
super.show(); //子类的普通方法中super关键字表示父类的原型对象
}
}
class S extends F{
static name="儿子";
static print(){
/*super关键字在使用的时候必须显式的指定他是函数还是对象,要么super后面带括号,要么要使用.运算符*/
// console.log(super); //报错
console.log(sup…
class S extends F{
static name="儿子";
static print(){
/*super关键字在使用的时候必须显式的指定他是函数还是对象,要么super后面带括号,要么要使用.运算符*/
// console.log(super); //报错
console.log(sup…
儿子
父级的静态函数
*/
let s = new S();
s.print();//调用实例方法
//输出结果:父级的普通函数