[JavaScript] 面向对象编程

JavaScript 是一种多范式语言,既支持函数式编程,也支持面向对象编程。在 ES6 引入 class 语法后,面向对象编程在 JavaScript 中变得更加易于理解和使用。以下将详细讲解 JavaScript 中的类(class)、构造函数(constructor)、继承、封装、多态,以及 this 的相关问题。


1. 为什么需要类与面向对象编程?

面向对象编程(Object-Oriented Programming,OOP)是一种以“对象”为核心的编程思想。通过类与对象的概念,可以更好地模拟现实世界的实体,提升代码的可重用性、可维护性和扩展性。

在 JavaScript 早期,使用函数和原型链实现面向对象的思想,语法复杂且容易出错。引入 class 后,语法更加直观。


2. 类(class)与构造函数(constructor)

2.1 类的基本语法

class 是用来定义对象蓝图的关键字,其中包含对象的属性和方法。

class Person {
    // 构造函数:定义对象的初始化逻辑
    constructor(name, age) {
        this.name = name; // this 代表当前实例
        this.age = age;
    }

    // 定义实例方法
    sayHello() {
        console.log(`Hello, my name is ${this.name}.`);
    }
}

// 创建类的实例
const person1 = new Person("Kevin", 25);
console.log(person1.name); // 输出:Kevin
person1.sayHello(); // 输出:Hello, my name is Kevin.

2.2 为什么需要构造函数?

constructor 是类的特殊方法,用于在创建对象时初始化属性。它的主要作用是:

  1. 设置对象的初始状态。
  2. 为每个实例创建唯一的属性。

2.3 静态方法(static methods)

静态方法是直接定义在类上的方法,而不是在实例上的方法。静态方法通常用于创建工具类或与实例无关的逻辑。

class MathUtils {
    static add(a, b) {
        return a + b;
    }
}

console.log(MathUtils.add(2, 3)); // 输出:5

3. 继承

继承允许我们定义一个类,继承另一个类的属性和方法,从而实现代码复用。

3.1 基本语法

使用 extends 实现继承,并通过 super() 调用父类的构造函数。

class Animal {
    constructor(name) {
        this.name = name;
    }

    makeSound() {
        console.log(`${this.name} is making a sound.`);
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name); // 调用父类的构造函数
        this.breed = breed;
    }

    makeSound() {
        console.log(`${this.name}, a ${this.breed}, barks.`);
    }
}

const dog = new Dog("Buddy", "Golden Retriever");
dog.makeSound(); 
// 输出:Buddy, a Golden Retriever, barks.

3.2 为什么需要继承?

  1. 代码复用:子类可以直接使用父类的属性和方法,避免重复代码。
  2. 逻辑扩展:子类可以添加自己的方法或重写父类的方法,实现特定功能。

4. 封装

封装是指将对象的内部状态隐藏起来,通过方法暴露必要的操作。这样可以保护数据的安全性,避免外部直接修改。

4.1 在 JavaScript 中实现封装

  1. 私有属性(ES6 之前的实现):
    通过闭包模拟私有属性。
function Person(name) {
    let _name = name; // 私有变量

    this.getName = function () {
        return _name;
    };

    this.setName = function (newName) {
        _name = newName;
    };
}

const person = new Person("Kevin");
console.log(person.getName()); // 输出:Kevin
person.setName("Feng");
console.log(person.getName()); // 输出:Feng
  1. 私有属性(ES6 新特性):
    使用 # 定义真正的私有属性。
class Person {
    #name;

    constructor(name) {
        this.#name = name;
    }

    getName() {
        return this.#name;
    }

    setName(newName) {
        this.#name = newName;
    }
}

const person = new Person("Kevin");
console.log(person.getName()); // 输出:Kevin
person.setName("Feng");
console.log(person.getName()); // 输出:Feng

5. 多态

多态是指不同的类在调用相同方法时,可以表现出不同的行为。这通常通过**方法重写(Method Overriding)**实现。

class Animal {
    makeSound() {
        console.log("Animal is making a sound.");
    }
}

class Dog extends Animal {
    makeSound() {
        console.log("Dog is barking.");
    }
}

class Cat extends Animal {
    makeSound() {
        console.log("Cat is meowing.");
    }
}

const animals = [new Dog(), new Cat()];
animals.forEach(animal => animal.makeSound());
// 输出:
// Dog is barking.
// Cat is meowing.

6. this 指向问题

6.1 为什么会有 this?

this 是 JavaScript 中一个动态绑定的关键字,其指向取决于函数的调用方式。


6.2 this 的常见指向规则

  1. 默认指向(全局对象):
    在非严格模式下,普通函数调用中的 this 指向全局对象 window
function showThis() {
    console.log(this);
}
showThis(); // 输出:window(浏览器环境下)
  1. 方法调用
    在对象的方法中,this 指向调用方法的对象。
const obj = {
    name: "Kevin",
    showThis() {
        console.log(this);
    },
};
obj.showThis(); // 输出:obj 对象本身
  1. 构造函数中的 this
    在构造函数中,this 指向新创建的对象。
function Person(name) {
    this.name = name;
}
const person = new Person("Kevin");
console.log(person.name); // 输出:Kevin
  1. 箭头函数中的 this
    箭头函数不会创建自己的 this,而是从外部作用域继承 this
const obj = {
    name: "Kevin",
    showThis: () => {
        console.log(this);
    },
};
obj.showThis(); // 输出:window 或 undefined(严格模式下)

6.3 解决 this 指向问题

  1. **使用 **bind
const obj = { name: "Kevin" };
function showName() {
    console.log(this.name);
}
const boundShowName = showName.bind(obj);
boundShowName(); // 输出:Kevin
  1. 使用箭头函数
const obj = {
    name: "Kevin",
    showThis() {
        const arrow = () => console.log(this.name);
        arrow();
    },
};
obj.showThis(); // 输出:Kevin

总结

JavaScript 的面向对象编程非常灵活,类的引入让代码更加清晰和直观。在实际开发中,熟练掌握类与对象、继承、封装、多态,以及 this 的指向规则,可以让你写出更加高效和可维护的代码。如果有任何疑问或需要补充代码示例,欢迎随时交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/959683.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

20250121在Ubuntu20.04.6下使用Linux_Upgrade_Tool工具给荣品的PRO-RK3566开发板刷机

sudo upgrade_tool uf update.img 20250121在Ubuntu20.04.6下使用Linux_Upgrade_Tool工具给荣品的PRO-RK3566开发板刷机 2025/1/21 11:54 百度:ubuntu RK3566 刷机 firefly rk3566 ubuntu upgrade_tool烧写详解 https://wiki.t-firefly.com/Core-3566JD4/03-upgrad…

基础项目——扫雷(c++)

目录 前言一、环境配置二、基础框架三、关闭事件四、资源加载五、初始地图六、常量定义七、地图随机八、点击排雷九、格子类化十、 地图类化十一、 接口优化十二、 文件拆分十三、游戏重开 前言 各位小伙伴们,这期我们一起学习出贪吃蛇以外另一个基础的项目——扫雷…

【动态规划】落花人独立,微雨燕双飞 - 8. 01背包问题

本篇博客给大家带来的是01背包问题之动态规划解法技巧. 🐎文章专栏: 动态规划 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅🚀 要开心要快乐顺便…

游戏steam_api64.dll文件缺失怎么办?无法找到指定的模块的解决方法

在使用Steam平台运行游戏时,有时会遇到“steam_api64.dll文件缺失,无法找到指定的模块”的错误提示。这个问题通常是由于该文件被误删、病毒感染、系统更新不兼容或游戏安装不完整等原因造成的。以下是一些有效的解决方法,帮助你解决steam_ap…

Linux学习笔记——网络管理命令

一、网络基础知识 TCP/IP四层模型 以太网地址(MAC地址): 段16进制数据 IP地址: 子网掩码: 二、接口管命令 ip命令:字符终端,立即生效,重启配置会丢失 nmcli命令:字符…

在 Windows 系统上,将 Ubuntu 从 C 盘 迁移到 D 盘

在 Windows 系统上,如果你使用的是 WSL(Windows Subsystem for Linux)并安装了 Ubuntu,你可以将 Ubuntu 从 C 盘 迁移到 D 盘。迁移过程涉及导出当前的 Ubuntu 发行版,然后将其导入到 D 盘的目标目录。以下是详细的步骤…

simulink入门学习01

文章目录 1.基本学习方法2.图形环境--模块和参数3.激活菜单---添加到模型3.1输入选项3.2添加到模型3.3更改运算3.4验证要求 4.乘以特定值--Gain模块4.1引入gain模块4.2更改增益参数4.3接入系统4.4大胆尝试 1.基本学习方法 今天突然想要学习这个simulink的相关知识,…

Linux的基本指令(上)

1.ls指令 语法:ls [选项] [目录或文件] 功能:对于⽬录,该命令列出该⽬录下的所有⼦⽬录与⽂件。对于⽂件,将列出⽂件名以及其他信息。 常用选项: -a 列出⽬录下的所有⽂件,包括以 . 开头的隐含⽂件。 -d 将…

一文详解Filter类源码和应用

背景 在日常开发中,经常会有需要统一对请求做一些处理,常见的比如记录日志、权限安全控制、响应处理等。此时,ServletApi中的Filter类,就可以很方便的实现上述效果。 Filter类 是一个接口,属于 Java Servlet API 的一部…

【算法】数论基础——唯一分解定理(算术基本定理)python

目录 定义进入正题热身训练实战演练扩展衍生判断一个数是否为完全平方数举一反三总结 定义 唯一分解定理:也叫做算数基本定理: 任意一个大于1的整数N,都可以唯一分解为若干个质数的乘积 换句话说,任何大于1的整数n可以表示为: 例如…

互联网医院成品|互联网医院开发|互联网医院搭建

在数字化医疗蓬勃发展的当下,互联网医院系统已成为医疗服务体系中至关重要的组成部分。它打破了传统医疗服务在时间和空间上的限制,为患者提供了更加便捷、高效的医疗服务。而一套完善的互联网医院系统,有几个功能是不能缺少的。 在线问诊功能…

Go的内存逃逸

Go的内存逃逸 内存逃逸是 Go 语言中一个重要的概念,指的是本应分配在栈上的变量被分配到了堆上。栈上的变量在函数结束后会自动回收,而堆上的变量需要通过垃圾回收(GC)来管理,因此内存逃逸会增加 GC 的压力&#xff0…

填充每个节点的下一个右侧节点指针力扣--116,117

目录 题目 思路 代码 题目 116 给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下: struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针&#xff0c…

钉钉群机器人设置——python版本

钉钉群机器人设置——python版本 应用场景钉钉界面操作程序开发效果展示 应用场景 由于工作需要,很多项目执行程序后出现报错信息无法第一时间收到,因此实时预警对于监控程序还是有必要。(仅个人观点) 参考文档及博客&#xff1a…

初步认识操作系统(Operator System)

目录 一、概念二、设计OS的目的三、定位四、操作系统上下的分级五、如何理解 "管理"六、总结 一、概念 任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。操作系统包括: 内核(进程管理,内存管理&#xff0c…

文明6mod发布并开源:更多的蛮族营地扫荡收益mod

更多的蛮族营地扫荡收益mod(More_Barbarian_Camp_RAID_luke) 效果为: 更多的蛮族营地扫荡收益,增加到100金币,适用于野蛮氏族模式 原版本的扫荡收益非常鸡肋~! mod下载链接: https://downlo…

社区养老服务平台的设计与实现(代码+数据库+LW)

摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对信息管理混乱,出错率高,信息安全性差&#…

websocket实现

由于安卓资源管理器展示的路径不尽相同,各种软件保存文件的位置也不一定一样.对于普通用户上传文件时,查找文件可能是一个麻烦的事情.后来想到了一个办法,使用pc端进行辅助上传. 文章目录 实现思路1.0 实现定义web与客户端通信数据类型和数据格式web端websocket实现web端对客户…

(一)HTTP协议 :请求与响应

前言 爬虫需要基础知识,HTTP协议只是个开始,除此之外还有很多,我们慢慢来记录。 今天的HTTP协议,会有助于我们更好的了解网络。 一、什么是HTTP协议 (1)定义 HTTP(超文本传输协议&#xff…

arcgis短整型变为长整型的处理方式

1.用QGIS的重构字段工具进行修改,亲测比arcgis的更改字段工具有用 2.更换低版本的arcgis10.2.2,亲测10.5和10.6都有这个毛病,虽然官方文档里面说的是10.6.1及以上 Arcgis10.2.2百度链接:https://pan.baidu.com/s/1HYTwgnBJsBug…