[JavaScript] 面向对象编程

news2025/1/28 1:01:06

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 的指向规则,可以让你写出更加高效和可维护的代码。如果有任何疑问或需要补充代码示例,欢迎随时交流!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows上通过Git Bash激活Anaconda

在Windows上配置完Anaconda后,普遍通过Anaconda Prompt激活虚拟环境并执行Python,如下图所示: 有时需要连续执行多个python脚本时,直接在Anaconda Prompt下可以通过在以下方式,即命令间通过&&连接,…

主机监控软件WGCLOUD使用指南 - 如何设置主题背景色

WGCLOUD运维监控系统,从v3.5.7版本开始支持设置不同的主题背景色,如下 更多主题查看说明 如何设置主题背景色 - WGCLOUD

C语言教程——文件处理(2)

目录 前言 一、顺序读写函数(续) 1.1fprintf 1.2fscanf 1.3fwrite 1.4fread 二、流和标准流 2.1流 2.2标准流 2.3示例 三、sscanf和sprintf 3.1sprintf 3.2sscanf 四、文件的随机读写 4.1fseek 4.2ftell 4.3rewind 五、文件读取结束的…

ios打包:uuid与udid

ios的uuid与udid混乱的网上信息 新人开发ios,发现uuid和udid在网上有很多帖子里是混淆的,比如百度下,就会说: 在iOS中使用UUID(通用唯一识别码)作为永久签名,通常是指生成一个唯一标识&#xf…

.NET9增强OpenAPI规范,不再内置swagger

ASP.NETCore in .NET 9.0 OpenAPI官方文档ASP.NET Core API 应用中的 OpenAPI 支持概述 | Microsoft Learnhttps://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/openapi/overview?viewaspnetcore-9.0https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/ope…

hot100_234. 回文链表

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。 示例 1: 输入:head [1,2,2,1] 输出:true 示例 2: 输入:head …

【超详细】ELK实现日志采集(日志文件、springboot服务项目)进行实时日志采集上报

本文章介绍,Logstash进行自动采集服务器日志文件,并手把手教你如何在springboot项目中配置logstash进行日志自动上报与日志自定义格式输出给logstash。kibana如何进行配置索引模式,可以在kibana中看到采集到的日志 日志流程 logfile-> l…

IPoIB(IP over InfiniBand)数据接收与发送机制详解

IPoIB(IP over InfiniBand)是一种在InfiniBand网络上实现IP协议的技术,它允许在InfiniBand网络上传输IP数据包。IPoIB通过将IP数据包封装在InfiniBand的数据包中,实现了在InfiniBand网络上的高效通信。本文将详细分析IPoIB如何接收…

Spring Boot - 数据库集成04 - 集成Redis

Spring boot集成Redis 文章目录 Spring boot集成Redis一:redis基本集成1:RedisTemplate Jedis1.1:RedisTemplate1.2:实现案例1.2.1:依赖引入和属性配置1.2.2:redisConfig配置1.2.3:基础使用 2&…

JAVAweb学习日记(八) 请数据库模型MySQL

一、MySQL数据模型 二、SQL语言 三、DDL 详细见SQL学习日记内容 四、DQL-条件查询 五、DQL-分组查询 聚合函数: 分组查询: 六、DQL-分组查询 七、分页查询 八、多表设计-一对多&一对一&多对多 一对多-外键: 一对一: 多…

Scratch游戏作品 | 僵尸来袭——生存大战,保卫你的领地!

今天为大家推荐一款刺激十足的Scratch射击生存游戏——《僵尸来袭》!在这个充满危机的世界里,僵尸不断向你袭来,利用你的战斗技能与策略道具生存下来,成为最后的幸存者!✨ 源码现已在小虎鲸Scratch资源站免费下载&…

C# 自定义随机字符串生成

目录 简介 调用方式: 详细说明 1.外层方法封装 2.定义字符组合 3.按长度生成 简介 随机字符串,包含数字,字母,特殊符号等,随机拼凑,长度可输入 为了生成效率,长度大于1024的&#xff0c…

【C++探索之路】STL---string

走进C的世界,也意味着我们对编程世界的认知达到另一个维度,如果你学习过C语言,那你绝对会有不一般的收获,感受到C所带来的码云风暴~ ---------------------------------------begin--------------------------------------- 什么是…

rust 发包到crates.io/ 操作流程 (十)

第一步github登录 https://crates.io/ 在项目里面login: cargo login ciol4sMwaR61YvzWniodRlssk6RfS4HcZTU --registry crates-io如果不想每次带 这个,就执行 vim ~/.cargo/config.toml 添加下面 [registry] default "crates-io"git a…

MongoDB部署模式

目录 单节点模式(Standalone) 副本集模式(Replica Set) 分片集群模式(Sharded Cluster) MongoDB有多种部署模式,可以根据业务需求选择适合的架构和部署方式。 单节点模式(Standa…

国自然重点项目|代谢影像组学只能预测肺癌靶向耐药的关键技术与应用|基金申请·25-01-25

小罗碎碎念 今天和大家分享一个国自然重点项目,项目执行年限为2019.01 - 2023.12,直接费用为294万。 项目聚焦肺癌靶向治疗中药物疗效预测难题,整合多组学与代谢影像数据展开研究。 在研究过程中,团队建立动物模型获取多维数据&am…

NFT Insider #166:Nifty Island 推出 AI Agent Playground;Ronin 推出1000万美元资助计划

引言:NFT Insider 由 NFT 收藏组织 WHALE Members、BeepCrypto 联合出品, 浓缩每周 NFT 新闻,为大家带来关于 NFT 最全面、最新鲜、最有价值的讯息。每期周报将从 NFT 市场数据,艺术新闻类,游戏新闻类,虚拟…

Word 中实现方框内点击自动打 √ ☑

注: 本文为 “Word 中方框内点击打 √ ☑ / 打 ☒” 相关文章合辑。 对第一篇增加了打叉部分,第二篇为第一篇中方法 5 “控件” 实现的详解。 在 Word 方框内打 √ 的 6 种技巧 2020-03-09 12:38 使用 Word 制作一些调查表、检查表等,通常…

Cpp::静态 动态的类型转换全解析(36)

文章目录 前言一、C语言中的类型转换二、为什么C会有四种类型转换?内置类型 -> 自定义类型自定义类型 -> 内置类型自定义类型 -> 自定义类型隐式类型转换的坑 三、C强制类型转换static_castreinterpret_castconst_castdynamic_cast 四、RTTI总结 前言 Hell…

4.flask-SQLAlchemy,表Model定义、增删查改操作

介绍 SQLAlchemy是对数据库的一个抽象 开发者不用直接与SQL语句打交道 Python对象来操作数据库 SQLAlchemy是一个关系型数据库 安装 flask中SQLAlchemy的配置 from flask import Flask from demo.user_oper import userdef create_app():app Flask(__name__)# 使用sessi…