【JS(ES6,ES5类的创建及继承)】

一、ES6的面向对象的语法(ES6创建类)

1、面向过程(了解)

核心是过程。即分析出解决问题的步骤,用函数将这些过程一一实现,然后依次调用。

2、面向对象

核心是对象。将需要解决的问题分解成一个个对象,这些对象不是解决问题的步骤。对象只是描述了在解决问题的过程中行为是什么(干了哪些工作)。

优点:
(1)封装性更强,模块化更深
(2)更容易实现复杂的业务逻辑
(3)容易维护、模块的复用率高

3、面向对象的特征

(1)封装性:对象是属性和行为的结合体

(2)多态性:同一个消息被不同的对象接收后,会产生不同的效果

(3)继承性:子类继承父类的部分属性和方法,子类中可以直接使用这些属性和方法

4、ECMAScript6(即ES6)的面向对象的语法

简介:ECMAScript6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了

(1)类:具有相同属性和行为的对象的集合

(2)对象:是类的实例化,是类的具体体现(类是对象的抽象,对象是类的具体体现)

(3)类的基本语法(ES6中定义类):

      class 类名
	  {
	     constructor([参数]){ //构造方法:初始化类的成员变量
		 属性(成员变量) 
		 }
		 行为(成员方法)
	  }

(4)ES6中创建对象(使用new运算符):

 对象名 = new 类名([参数])//在内存中开辟了一个存储空间

详述:

注意:a、类名:首字母大写 b、成员方法名:动词开头.驼峰命名,表示某种行为。

构造方法: a、作用是初始化对象 b、调用:不能显式调用,而是通过类名调用.

this指针:指当前的对象

属性和方法的使用:a、属性:对象名.属性 b、方法:对象名.方法名([参数])

☀️举个例子,理解一下:

class Person{
    constructor(name){//构造方法,初始化类的成员变量,
        this.name=name//this:代表是当前对象,谁调用这个对象,this就是谁

    }
}
//1.类的构造方法不会显式的调用,而是通过类名调用
//2.this:代表当前的对象t1
//3.this.name:它表示当前对象t1的属性name
 var t1 = new Person('刘备')//这句话的意思是在内存中开辟了一个存储空间,new是申请了一块存储空间,s1就是复制了它的地址
 var p1 = new Person('周瑜')
 console.log(t1)
 console.log(p1)

在这里插入图片描述
☀️举个例子,理解一下:

class Student{
    constructor(id,name,sex){//构造方法,带有三个参数,但不是里面只有三个属性,是指给这三个属性(参数)进行赋值
        this.id=id;          //构造方法:①作用:初始化对象②调用:不能显式调用,而是通过类名对象
        this.name=name;      //初始化变量的这时候的this指针,指的是当前对象,这时候没有明确的对象,当var s1对象被创建时,this才有了明确的对象s1。
        this.sex=sex;
        this.age=18;//不是参数的属性值给死,固定的,后面可以更改
        this.address=null;//不是参数的属性值给死,固定的,后面可以更改

    }
    show(){//成员方法(成员函数)
        console.log('学号:',this.id)
        console.log('姓名:',this.name)
        console.log('性别:',this.sex)
        console.log('年龄:',this.age)
        console.log('地址:',this.address)
    }
}
var s1 =new Student(1001,'郭靖','男')//s1就是一个对象,是Student类的一个实例化,
s1.show()
//属性的使用:对象名.属性名
s1.age=24
s1.address='蒙古'
//方法的使用:对象名.方法名([参数])
s1.show()  

在这里插入图片描述

5、练习

1、定义学生类(Student),属性有name、gender、age、address、phone,
行为(方法)有showInfo,用于显示学生信息。创建对象测试类。

 class Student{
     constructor(name,gender){
         this.name=name
         this.gender=gender
         this.age=18   //定义初始化成员变量
         this.address=null
         this.phone=null
     }
     showInfo(){//成员方法,
         let info='姓名:'+this.name+'\n'+
         '性别:'+this.gender+'\n'+
         '年龄:'+this.age+'\n'+
         '电话:'+this.phone
         console.log(info)
     }
 }
 var s1 =new Student('郭靖','男')
 s1.age=24
 s1.address='桃花岛'
 s1.phone='1347890977'//访问属性并将其更改
 s1.showInfo()//调用方法显示

在这里插入图片描述
2、创建一个电脑类(Computer) 有颜色(color)、重量(weight)、品牌(brand)、
型号(type)属性, 有看电影(watch)、听音乐(listen)、打游戏(play)和敲代码(coding)方法。
创建对象,在调方法时分别打印 “我在 看电影/听音乐/打游戏/敲代码”。

 class Computer{
     constructor(){
         this.color=null
         this.weight=0
         this.brand=null
         this.type=null
     }
     watchMovie(){
         let watch='我在看电影'
         console.log(watch)
     }
     listenMusic(){
         let listen='我在听音乐'
         console.log(listen)
     }
     playYouxi(){
         let play='我在玩游戏'
         console.log(play)
     }
     codingDai(){
         let coding='我在敲代码'
         console.log(coding)
     }
     show(){
        var info='品牌:'+this.brand+'\n'+
              '型号:'+this.type+'\n'+
              '重量:'+this.weight+'\n'+
              '颜色:'+this.color
              console.log(info)
     }
 }
 var s2=new Computer()
 s2.color='grey'
 s2.weight='100'
 s2.brand='联想'
 s2.type='core i7'
 s2.show()
 s2. watchMovie()
 s2.listenMusic()
 s2.playYouxi()
 s2.codingDai()

在这里插入图片描述
3、创建类Temperature,包含成员变量degree(表示温度)以及成员方法,ToFahrenheit(摄氏温度转为华氏温度)和ToCelsius(华氏温度转摄氏温度)
其中: 摄氏度= (华氏温度-32)5/9,华氏度= 摄氏度9/5+32
创建对象,显示转换结果。

 class Temperature{
     constructor(){
         this.degree=null
     }
     ToFaherenheit(){
        var sheshi
        sheshi = (this.degree-32)*5/9
        console.log(sheshi)
     }
     ToCelsius(){
        var huashi
       huashi=this.degree*9/5+32
       console.log(huashi)
     }
 }
 var s3=new Temperature()
 s3.degree=45
 s3.ToFaherenheit()
 s3. ToCelsius()

在这里插入图片描述

二、ES6中类的继承

ES6中类的继承:子类可以继承父类的部分属性和方法,在继承后子类还可以定义自己独有的属性和方法

(1)子类(派生类):继承的类

(2)父类(超类,基类):被继承的类

(3)语法格式:

  class 子类名 extends 父类名{
      构造方法(){}
	  成员方法
    }

☀️举个例子:

class Father{
    constructor(){}
    money(){
    console.log(100)
    }
}
class Son extends Father{//子类Son继承Father
}
//创建子类对象
var s1 =new Son()
s1.money()//子类继承父类的方法

在这里插入图片描述
(4)子类访问父类的属性和方法

A、使用super关键字调用父类的构造方法: super([参数])
以下三个点需要注意

(a)从父类继承过来的属性必须通过super调用父类的构造方法进行初始化

☀️举个例子:

class Father{
    constructor(x,y){
        this.x=x  //this.x中的x表示父类Father的属性
        this.y=y  //this.y中的y表示父类Father的属性
    }
    getSum(){//获取x和y的值
        console.log(this.x+this.y)
    }
}
class Son extends Father{//子类Son继承Father
//调用父类的构造方法初始化x和y的属性
constructor(x,y){//是子类Son自己的构造方法
   super(x,y)//调用父类的构造方法 //注意:从父类继承过来的属性必须通过super来初始化

}
}
var s1=new Son(10,20)
s1.getSum()

在这里插入图片描述

(b)super([参数])必须作为子类构造方法的第一条语句
(c)无论是父类或子类属性的初始化都必须通过构造方法来完成

class Father{
        constructor(x,y){
            this.x=x  //this.x中的x表示父类Father的属性
            this.y=y  //this.y中的y表示父类Father的属性
        }
        getSum(){//获取x和y的值
            console.log(this.x+this.y)
        }
    }
    class Son extends Father{//子类Son继承Father
    //调用父类的构造方法初始化x和y的属性
    constructor(x,y,z){//是子类Son自己的构造方法
    super(x,y)//调用父类的构造方法   
    //super([参数])必须作为子类构造方法的第一条语句,因为子类继承先调用的是父类构造方法,不然会报错。
        this.z=z //this.z中的z是Son自己的属性
    }

    }
    var s1=new Son(10,20)
    s1.getSum()
    

报错显示:
在这里插入图片描述
正确显示:
在这里插入图片描述
B、使用super调用父类的普通成员方法:super.方法名([参数])
☀️举个例子


    class Father{
        constructor(x,y){
            this.x=x  //this.x中的x表示父类Father的属性
            this.y=y  //this.y中的y表示父类Father的属性
        }
        getSum(){//获取x和y的值
            console.log(this.x+this.y)
        }
    }
    class Son extends Father{//子类Son继承Father
    //调用父类的构造方法初始化x和y的属性
    constructor(x,y,z){//是子类Son自己的构造方法
       super(x,y)//调用父类的构造方法 
       //无论子类还是父类,属性的初始化,都必须通过构造方法来完成
       this.z=z //this.z中的z是Son自己的属性
    }
    Sum(){//子类Son自己的成员方法
        super.getSum()//通过super调用父类的getSum()方法
       
    }
    }
    var s1=new Son(10,20)
    s1.Sum()

在这里插入图片描述
(5)方法覆盖(override)

方法覆盖(override):当子类的成员方法和父类的成员方法重名时,子类的方法会覆盖父类的同名方法。

小引申: 方法重载(OverLoad):给同一个方法(函数)传递不同的参数,其执行结果不同。

☀️举个例子:

class Father{
    constructor(x,y){
        this.x=x  //this.x中的x表示父类Father的属性
        this.y=y  //this.y中的y表示父类Father的属性
    }
    getSum(){//获取x和y的值
        // console.log(this.x+this.y)
        return (this.x+this.y)
    }
}
class Son extends Father{//子类Son继承Father
//调用父类的构造方法初始化x和y的属性
constructor(x,y,z){//是子类Son自己的构造方法
   super(x,y)//调用父类的构造方法 
   //注意:①从父类继承过来的属性必须通过super调用父类的构造方法来进行初始化
   //②super([参数])必须作为子类构造方法的第一条语句,因为子类继承先调用的是父类构造方法。
   //③无论子类还是父类,属性的初始化,都必须通过构造方法来完成
   this.z=z //this.z中的z是Son自己的属性
}
getSum(){//子类Son自己的成员方法
    let l=super.getSum()+this.z
    console.log(l)
}
}
var s1=new Son(10,20,30)
s1.getSum()

在这里插入图片描述
由上图运行结果可知,因为子类的方法和父类的方法同名,调用同名的方法时,子类的方法会覆盖父类。

(6)练习
请编码实现动物世界的继承关系: 动物(Animal)具有行为:吃(eat)、睡觉(sleep)
动物包括:兔子(Rabbit)、老虎(Tiger)、鱼(Fish) 这些动物吃的行为各不相同(兔子吃草,老虎吃肉、鱼吃浮游生物);睡觉的行为也不一样。

class Animals{//抽象的基类,不能实例化
    constructor(){
       
    }
    Eat(){
          
    }
    Sleep(){
   
    }
}
class Rabbit extends Animals{
   constructor(){
       super()
   }
Eat(){
    console.log('兔子吃草')
}
Sleep(){
    console.log('兔子在睡觉')
   }
}
class Tiger extends Animals{
    Eat(){
        console.log('老虎吃肉')
    }
    Sleep(){
        console.log('老虎在睡觉')
       }

}
class Fish extends Animals{
    Eat(){
        console.log('鱼再吃浮游植物')
    }
    Sleep(){
        console.log('鱼在睡觉')
       }
}
var s1=new Rabbit()
s1.Eat()
s1.Sleep()
var s2=new Tiger()
s2.Eat()
s2.Sleep()
var s3=new Fish ()
s3.Eat()
s3.Sleep()

在这里插入图片描述

三、ES5中创建类

1、创建构造函数,在构造函数中定义属性和方法

(1)构造方法名就是类名,更推荐ES6创建方式
(2)和使用class创建类的区别
a、构造方法创建类:属性和方法都在构造方法中定义
b、使用class创建类:属性在构造方法中定义,方法在构造方法外

☀️ES5定义类例子,便于理解:

function Person(name,sex){//构造函数,name,sex是构造函数的参数
    this.name=name//this.name中的name是Person类的属性
    this.sex=sex//this.sex中的sex是Person类的属性
    
    this.sleep=function(){//sleep是成员方法,函数表达式
        console.log(this.name+'我在睡觉')
    }
    this.eat=function(){//eat是成员方法,函数表达式
        console.log(this.name+'我在吃饭')
    }
}
//创建对象
var p1=new Person('黄蓉','女')
console.log('姓名:',p1.name)
console.log('性别:',p1.sex)
p1.sleep()
p1.eat()

在这里插入图片描述
☀️ES6定义类例子,便于理解:

class Person{
    constructor(name,sex){
        this.name=name
        this.sex=sex
}
    sleep(){//sleep是成员方法,函数表达式
        console.log(this.name+'我在睡觉')
    }
    eat(){//eat是成员方法,函数表达式
        console.log(this.name+'我在吃饭')
    }
}
//创建对象
var p1=new Person('黄蓉','女')
console.log('姓名:',p1.name)
console.log('性别:',p1.sex)
p1.sleep()
p1.eat()

在这里插入图片描述

// 使用类表达式创建类
var Person=class{
    constructor(name,sex){
        this.name=name
        this.sex=sex
    }
    sleep(){//sleep是成员方法,函数表达式
        console.log(this.name+'我在睡觉')
    }
    eat(){//eat是成员方法,函数表达式
        console.log(this.name+'我在吃饭')
    }
}
//创建对象
var p1=new Person('黄蓉','女')
console.log('姓名:',p1.name)
console.log('性别:',p1.sex)
p1.sleep()
p1.eat()


四、ES5类的继承

ES6之前并没有给我们提供 extends 继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。

1、call()

调用这个函数, 并且修改函数运行时的 this 指向

fun.call(thisArg, arg1, arg2, ...) // thisArg :当前调用函数 this 的指向对象
//arg1 , arg2 :传递 的其他 参数 

call()的两个作用:

(1) call() 可以调用函数

fn.call();

(2)call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o这个对象

fn.call(第一个改变this指向,后面是普通实参)
// call 方法
        function fn(x, y) {
            console.log('我想喝手磨咖啡');
            console.log(this);
            console.log(x + y);
        }
        var o = {
            name: 'andy'
        };
        // fn();
        // 1. call() 可以调用函数
        // fn.call();
        // 2. call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o这个对象
        fn.call(o, 1, 2);

在这里插入图片描述

2、 借用构造函数继承父类型属性

核心原理: 通过 call() 把父类型的 this 指向子类型的 this ,这样就可以实现子类型继承父类型的属性。

    // 父类
    function Person(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
      }
      // 子类
      function Student(name, age, sex, score) {
        Person.call(this, name, age, sex);  // 此时父类的 this 指向子类的 this,同时调用这个函数
        this.score = score;
      }
      var s1 = new Student('张三', 18, '男', 100);
      console.log(s1); 

在这里插入图片描述

// 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age);
            this.score = score;
        }
        var son = new Son('刘德华', 18, 100);
        console.log(son);

在这里插入图片描述

3、借用原型对象继承父类型方法

一般情况下,对象的方法都在构造函数的原型对象中设置,通过构造函数无法继承父类方法。

核心原理:

① 将子类所共享的方法提取出来,让子类的 prototype 原型对象 = new 父类 ()
② 本质:子类原型对象等于是实例化父类,因为父类实例化之后另外开辟空间,就不会影响原来父类原型对象
③将子类的 constructor 从新指向子类的构造函数.

// 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        Father.prototype.money = function() {
            console.log(100000);
 
        };
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age);
            this.score = score;
        }
        // Son.prototype = Father.prototype;  这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
        Son.prototype = new Father();
        // 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
        Son.prototype.constructor = Son;
        // 这个是子构造函数专门的方法
        Son.prototype.exam = function() {
            console.log('孩子要考试');
 
        }
        var son = new Son('刘德华', 18, 100);
        console.log(son);
        console.log(Father.prototype);
        console.log(Son.prototype.constructor);

在这里插入图片描述

五、类的静态成员和实例成员:又称为类成员

1、实例成员(成员变量和成员方法):属于类的实例(具体的对象)

2、静态成员:包括静态的成员变量和静态的成员方法。不属于某个具体的对象,而是类的所有对象共享的成员。是通过类名(或构造方法名)访问的成员

☀️举个例子,便于理解:

//ES5
function Student(s,name,sex){
    // this.school=school  //this.school是实例对象,school定义成一个实例对象是不合适的,因为学校属于共享的,并不是一个人独有的。
    Student.school=s //school是静态的成员变量,Student的所有对象共享该成员。
    this.name=name//this.name是实例对象
    this.sex=sex//this.sex是实例对象
    this.display =function(){
        let str ='学校:'+Student.school+'\n姓名:'+this.name+'\n性别:'+this.sex
        console.log(str)
    }
    Student.sayHello=function(){  //静态成员方法
        console.log('Hello'+Student.school)
    }
}

var s1 = new Student('西安交通大学','周瑜','男')
var s2 = new Student('西安交通大学','小乔','女')
var s3 = new Student('西安交通大学','黄盖','男')
Student.school='西安邮电大学'
s1.display()
s2.display()
s3.display()
Student.sayHello()

在这里插入图片描述
强调:在ES6中定义静态成员方法时必须用static关键字修饰.
☀️例子如下:

//ES6
class Student{
    constructor(s,name,sex){
        // this.school=school  //this.school是实例对象,school定义成一个实例对象是不合适的,因为学校属于共享的,并不是一个人独有的。
        Student.school=s //school是静态的成员变量,Student的所有对象共享该成员。
        this.name=name//this.name是实例对象
        this.sex=sex//this.sex是实例对象
    }
    display(){
    let str ='学校:'+Student.school+'\n姓名:'+this.name+'\n性别:'+this.sex
    console.log(str)
   }
    static sayHello(){  //在ES6定义类的静态成员方法
        console.log('Hello'+Student.school)
    }

}
var s1 = new Student('西安交通大学','周瑜','男')
var s2 = new Student('西安交通大学','小乔','女')
var s3 = new Student('西安交通大学','黄盖','男')
Student.school='西安邮电大学'
s1.display()
s2.display()
s3.display()
Student.sayHello()

在这里插入图片描述

六、类的本质

  1. class本质还是function.

  2. 类的所有方法都定义在类的prototype属性上

  3. 类创建的实例,里面也有__proto__ 指向类的prototype原型对象

4.所以ES6的类它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

5.所以ES6的类其实就是语法糖.

  1. 语法糖:语法糖就是一种便捷写法. 简单理解, 有两种方法可以实现同样的功能, 但是一种写法更加清晰、方便,那么这个方法就是语法糖
// ES6 之前通过 构造函数+ 原型实现面向对象 编程
        // (1) 构造函数有原型对象prototype 
        // (2) 构造函数原型对象prototype 里面有constructor 指向构造函数本身
        // (3) 构造函数可以通过原型对象添加方法
        // (4) 构造函数创建的实例对象有__proto__ 原型指向 构造函数的原型对象
        // ES6 通过 类 实现面向对象编程 
        class Star {
 
        }
        console.log(typeof Star);
        // 1. 类的本质其实还是一个函数 我们也可以简单的认为 类就是 构造函数的另外一种写法
        // (1) 类有原型对象prototype 
        console.log(Star.prototype);
        // (2) 类原型对象prototype 里面有constructor 指向类本身
        console.log(Star.prototype.constructor);
        // (3)类可以通过原型对象添加方法
        Star.prototype.sing = function() {
            console.log('刘欢');
 
        }
        var d = new Star();
        console.log(d);
        // (4) 类创建的实例对象有__proto__ 原型指向 类的原型对象
        console.log(d.__proto__ === Star.prototype);
        

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值