初步认识js中的类

203 阅读5分钟

什么是类

在js中,类的本质就是一个函数,是基于原型的语法糖,底层仍然是函数和原型链,因为JavaScript采用基于原型的面向对象模式,与传统基于类的语言有所不同,导致它并不像传统的面向对象一样,但是js为了也有这样的一个概念所以搞出来了一个跟类相似的东西,ES6引入的class关键字让面向对象编程更直观,但底层机制不变

// 类本质是函数
class Dog{}
console.log(typeof Dog); // "function"
console.log(Dog.prototype.constructor === Dog); // true

image.png

类和对象之间的关系

类:类是一个抽象的概念,比如在生活中,我们常常把所有的狗统一都叫狗,那么狗就是一个类,而所有的狗都有眼睛嘴巴鼻子尾巴之类的共同特征,我们将其称作实例属性,与之对应的,每个狗都会汪汪叫,都会摇尾巴,而这种行为叫做实例方法。

对象:对象是一个具体的实例,比如你自己有一个狗狗,它的名字叫旺财,7岁了,这个就是一个具体的对象。

关系:类是对象的模板,对象是类的实例。

类的实例属性和方法怎么定义

定义实例属性分为两种情况:

  1. 会变的:还是以狗类为例,当我们将这个类实例化的时候,每个狗的名字、年龄、毛发、性别都会不一样,所以对于这种我们需要用到“constructor” constructor:当我们创建一个实例化对象的时候,类会自动执行这个函数,在这里我们通常会进行一些数据的初始化操作,如果没有进行任何操作,类也会自动帮我们调用这个函数
class Dog{
    name="";
    age="";
    sex="";
    hair="";
    constructor(name,age,sex,hair){
        this.name=name;
        this.age=age;
        this.sex=sex;
        this.hair=hair;
    }

    cry(){
        console.log("汪汪汪");
    }

    cry2=function(){
        console.log("汪汪");
    }
}

let wangCai = new Dog("旺财", 8, "公", "光泽亮滑");
console.log(wangCai);

这里需要注意,这两个方法的创建不止止是形式上的区别:

image.png 看出来了吗,我们的cry2是直接挂载在自身上的,而cry是挂载在原型上的,所以这里建议类中的方法都用 “方法名(){}” 来定义

  1. 不会变的:直接赋值就行了
class Dog{
    name="旺财";
    age=20;
    ...
}

类的静态属性和方法怎么定义

在js中静态属性是指直接定义在类本身上的属性,而不是定义在实例对象上的属性,静态属性用 static 关键字来声明,并且只能通过类本身来访问

//定义
class Dog{
    static name="狗";
    static cry(){
        console.log("汪汪汪");
    }
}
// 使用
console.log(Dog.name);
Dog.cry();

es6类的继承

继承:一个子类继承一个父类(基类) 优点: 1. 子类会拥有父类的所有属性和方法 2. 能重复利用父类中的所有代码

例子:还是以我们的狗来举例,世界上的所有狗狗都可以叫狗,但是狗还有品种之间的区别,有柯基、哈士奇、边牧、拉布拉多等等,这个时候就可以以狗为基类,不同品种的狗为子类来创建一条狗

//创建父类(基类)
class Dog {
    constructor(name, age) {
        this.name = name;
        this.age = age
    }
    cry(){
        console.log("汪汪汪");
    }
    wagTail() {
        console.log(`${this.name}开心地摇着尾巴`);
    }
}
//创建子类
class Husky extends Dog {
    variety = "";
    characteristic = "";
    breed = "哈士奇";
    constructor(variety,characteristic, name, age) {
        super(name, age);
        this.variety = variety;
        this.characteristic = characteristic;
    }
    // 改写父类的cry方法
    cry(){
        console.log("嗷呜~~~");
    }
    // 哈士奇特有的拆家技能
    destroyFurniture() {
        console.log(`${this.name}正在疯狂拆家!`);
    }
}

// 创建哈士奇实例
let husky = new Husky("哈士奇","中等体型的犬种,身体修长,毛发浓密,颜色通常为黑色、白色、灰色、银色等,是一种非常活泼、好动的狗狗,需要大量的运动和刺激", "旺财", 8)
console.log(husky);
// 访问属性
console.log("名字:", husky.name);
console.log("品种:", husky.breed);
console.log("特征:", husky.characteristic);
// 调用方法
husky.cry();
husky.wagTail();
husky.destroyFurniture();

image.png

在面向对象的思想中,有三大特征--封装、继承、多态。而类的继承是面向对象编程的核心,在这个例子中,他让子类能够:

  • 继承父类的所有特征:就像小狗天生就会摇尾巴,会汪汪叫
  • 添加专属特征:不同品种的狗狗有独特的外貌和性格
  • 改写父类行为:哈士奇有独特的“狼嚎”,而非普通的犬吠

继承的三大核心优势:

  • 代码复用:不再重复编写基础代码,父类的所有属性和方法自动传承个子类
  • 功能扩展自由:子类可以添加专属特征,让每个“品种”都有不同的特征
  • 多态灵活:重写父类方法,让不同子类对同一指令做出不同响应

es5之前的继承

在es6“class”关键字出来之前,js都是通过构造函数来模仿类,下面将通过简单的代码来实现一下(了解一下就够了)

// 定义父类构造函数
function Dog(name, age) {
    this.name = name;
    this.age = age;
}
// 在原型上添加方法,实现所有实例共享
Dog.prototype.cry = function () {
    console.log("汪汪汪");
}
Dog.prototype.wagTail = function () {
    console.log(this.name + "开心地摇着尾巴");
}

// 定义子类构造函数
function Husky(variety, characteristic, name, age) {
    // 调用父类构造函数 (继承属性)
    Dog.call(this, name, age);
    // 子类特有属性
    this.variety = variety;
    this.characteristic = characteristic;
    this.breed = "哈士奇";
}
// 建立原型链 (继承方法)
Husky.prototype = Object.create(Dog.prototype);
// 修复constructor指向
Husky.prototype.constructor = Husky;
// 添加子类特有方法
Husky.prototype.destroyFurniture = function () {
    console.log(this.name + "正在疯狂拆家!");
};
// 重写父类方法
Husky.prototype.cry = function () {
    console.log("嗷呜~~~");
};

// 创建哈士奇实例
let husky = new Husky(
    "哈士奇",
    "中等体型的犬种,身体修长,毛发浓密,颜色通常为黑色、白色、灰色银色等,是一种非常活泼、好动的狗狗,需要大量的运动和刺激",
    "旺财",
    8
);
console.log(husky);
// 访问属性
console.log("名字:", husky.name);
console.log("品种:", husky.breed);
console.log("特征:", husky.characteristic);
// 调用方法
husky.cry();
husky.wagTail();
husky.destroyFurniture();