Js面向对象

embedded/2024/10/17 12:28:01/

程序就是对现实世界的抽象,一个事物抽象到程序中后就变成了对象,在程序的世界中,一切皆对象

面向对象的编程指,程序中的所有操作都是通过对象来完成

做任何事情之前都需要先找到它的对象,然后通过对象来完成各种操作

一个事物通常由两部分组成:数据和功能

  • 一个对象由两部分组成:属性和方法

  • 事物的数据到了对象中,体现为属性

  • 事物的功能到了对象中,体现为方法

const user = {// 添加属性name:"seven",age:18,weight:100,// 添加方法get_info(){console.log(`姓名:${this.name},年龄:${this.age},体重:${this.weight}`)},set_age(age){this.age = age}
}

类 calss

  • 使用Object创建对象:

    无法区分不同类型的对象

    不方便批量创建对象

  • 通过class创建对象

    类是对象模板,可以将对象中的属性和方法直接定义在类中,定义后,就可以直接通过类来创建对象

    通过同一个类创建的对象,我们称为同类对象可以使用instanceof来检查一个对象是否是由某个类创建如果某个对象是由某个类所创建,则我们称该对象是这个类的实例

    语法:calss 类名{} 、const 类名 = claskk{}

    通过类创建对象:new 类名()

        class User {}// User() : 构造函数const u1 = new User()console.log(u1 instanceof User) // true

类属性

        class User {name = "mickey" // 实例属性,只能通过实例访问 const u = new User() u.namestatic age = 18 // 静态属性(类属性),只能通过类去访问,User.age}// 使用new关键字调用构造函数User创建一个新的对象实例,即实例化对象const  user = new User()console.log(user.name) // mickeyuser.city = "Beijing"console.log(user.city) // Beijing

类方法

        class User {name = "mickey"static age = 18// 添加方法-实例方法(不建议使用)sayHello = function (){console.log("hello world")}// 实例方法,通过实例.方法名调用(建议使用)printName(){console.log(this.name) // 实例方法中this就是当前实例}// 静态方法(类方法),通过类.方法名调用static test(){console.log(this.age) // 静态方法中this指向的是当前类}}const  user = new User()user.sayHello()user.printName()User.test()

构造函数

   class User {// 在类中直接指定实例属性的值时,创建的所有对象属性都是这个值name = "mickey"}

       class User {// 在类中可以添加一个特殊的方法constructor// 该方法我们称为构造函数(构造方法)// 构造函数会在我们调用类创建对象时执行// 即该类实例化的时候会直接执行constructor(name,age) {// 可以在构造函数给实例属性赋值,构造函数中this表示当前所创建的对象this.name = namethis.age = age}}const  u1 = new User("l",18)console.log(u1) // {name: 'l', age: 18}const  u2 = new User("q",28)console.log(u2) // {name: 'q', age: 28}

封装、继承、多态

面向对象三大特性:封装、继承、多态

封装

数据安全

  • 对象就是一个用来存储不同属性的容器

  • 对象不仅存储属性,还要负责数据的安全

  • 直接添加到对象中的属性,并不安全,因为它们可以被任意的修改

  1. 私有化数据

    将需要保护的数据设置为私有,只能在类内部使用,属性私有化在属性前面加#表示私有属性, #name

  2. 提供setter和getter方法来开放对数据的操作

    通过类内部提供的方法获取、修改私有属性

模块化与可维护性

封装可以使代码更加模块化,将相关的数据和功能封装在一个对象或模块中。这样可以使代码结构更加清晰,易于理解和维护

可以提供统一的接口来访问和操作数据,确保外部代码以一致的方式与对象进行交互。

例如,一个封装良好的对象可以提供一组方法来执行特定的操作,外部代码不需要了解内部的实现细节,只需要调用这些方法即可

    class User {// 私有属性必须先声明// 声明赋值的私有属性#name = "q"// 声明未赋值的私有属性#ageconstructor(age) {this.#age = age}getAge(){return this.#age}getName() {return this.#name  // 获取私有属性name}setName(name) {if (name != null){this.#name = name // 修改私有属性name}}}const user = new User(67)console.log(user.getName())console.log(user.getAge())user.setName()

通过getter和setter获取和设置私有属性值

        class User {#name// getter 获取name属性值get name(){return this.#name}// setter 设置name属性值set name(name){this.#name = name}}const  user = new User()user.name = "l"console.log(user.name) 

多态

在JS中不会检查参数的类型,所以这就意味着任何数据都可以作为参数传递

要调用某个函数,无需指定的类型,只要对象满足某些条件即可

多态为我们提供了灵活性

  class  User{constructor(name) {this.name = name}}const  u1 = new  User("l")const  u2 = new  User("q")function sayHello(obj){console.log("hello ",obj.name)}sayHello(u1)sayHello(u2)=

继承

可以通过extends关键来完成继承

  • 当一个类继承另一个类时,就相当于将另一个类中的代码复制到了当前类中

  • 继承发生时,被继承的类称为 父类(超类),继承的类称为 子类

  • 通过继承可以减少重复的代码,并且可以在不修改一个类的前提对其进行扩展

   class  User{constructor(name) {this.name = name}getInfo() {console.log(this.name)}}// 使用extends关键字 Admin继承User类class Admin extends User{}const a = new Admin("l")a.getInfo()

通过继承可以在不修改一个类的情况下对其进行扩展

面向对象OCP开闭原则:程序应该对修改关闭,对扩展开放

        // 使用extends关键字 Admin继承User类// 在子类中,可以通过创建同名方法来重写父类的方法class Admin extends User{// 重写构造函数constructor(name) {// 重写构造函数时,构造函数的第一行代码必须为super()super(name);this.name = name}// 重写getInfo方法getInfo(){super.getInfo() // 通过super调用父类的getInfo方法console.log("名字是:",this.name)}}const a = new Admin("l")a.getInfo()

对象结构

对象中存储属性的区域实际有两个:

1、对象自身

直接通过对象所添加的属性,位于对象自身中

在类中通过key=value的形式添加属性、方法,位于对象自身中

2、原型对象(prototype)

对象中还有一些内容,会存储到其他的对象里

对象中会有一个属性用来存储原型对象,这个属性叫做__proto__

原型对象也负责为对象存储属性

我们访问对象中的属性时,会优先访问对象自身的属性,

对象自身不包含该属性时,才会去原型对象中寻找

会添加到原型对象中的情况:

在类中通过xxx(){}方式添加的方法,位于原型中

主动向原型中添加的属性或方法

      class  User {name = "l"  // 存储对象自身get = function (){}  // 存储对象自身set(){} // 存储原型对象}// 对象本身const user = new User() 

原型对象数据结构

        // 访问原型对象console.log(user.__proto__)// 访问原型对象console.log(Object.getPrototypeOf(user))

原型对象中的数据:

           1. 对象中的数据(属性、方法等),比如User.set()方法2. constructor (对象的构造函数)

原型对象也有对应的原型对象,构成一条原型链,根据对象的复杂程度不同,原型链的长度也不同

// 访问user对象的原型对象的原型对象       
console.log(user.__proto__.__proto__)

原型链:

  • 读取对象属性时,会优先对象自身属性,

  • 如果对象中有,则使用,没有则去对象的原型中寻找

  • 如果原型中有,则使用,没有则去原型的原型中寻找

  • 直到找到Object对象的原型(Object的原型没有原型(为null))

  • 如果依然没有找到,则返回undefined

  • 作用域链,是找变量的链,找不到会报错

  • 原型链,是找属性的链,找不到会返回undefined

原型的作用

// 所以的同类型对象的原型对象都是同一个,也就意味着同类型对象的原型链是一样的
var u1 = new  User()
var u2 = new  User()
console.log(u1.__proto__ === u2.__proto__) // true

  • 所有同类型对象的原型链都是一个,原型就相当于是一个公共的区域,只需要创建一个可以被所有该类实例访问

  • 在对象中有些值是对象独有的,比如属性,每个对象都应该有自己值,有些值对于每个对象都是一样的,像各种方法,对于一样的值没有必要重复创建,比如set()方法,在原型中,new100个对象只会创建1次,而不是创建100次

// 对于某些是每个对象独立的方法,可以使用x=y的方式存储在对象真实    
class  User {get = function (){}  // 存储对象自身,每个对象创建一个set(){} // 存储原型对象,原型链共用,多个对象不会重复创建}

  • JS中继承就是通过原型来实现的, 当继承时,子类的原型就是一个父类的实例

        // 继承Userclass  Admin extends User{}const  a = new Admin()// user实例 --> object --> Object原型 --> nullconsole.log(a.__proto__.__proto__.__proto__.__proto__)

//Object.create()是 JavaScript 中用于创建一个新对象的方法,这个新对象的原型可以指定为某个已有的对象
/*Object.create(proto, [propertiesObject])
proto:新创建对象的原型对象,可以是一个已有的对象,如果null,则新创建的对象没有原型,不会继承任何属性和方法
propertiesObject(可选):包含属性描述符的对象,用于定义新对象自身的属性当将 proto 参数设置为 null 时,可以创建一个没有原型的对象。这种对象通常用于存储临时数据或实现特定的算法,以避免意外地访问到原型链上的属性*/const parent = {sayHello() {console.log('Hello from parent')}}const child = Object.create(parent)child.sayHello()

// 创建一个没有原型的新对象,定义了一个名为 name 的属性,属性值为 john,属性全保险是可写、可枚举、可配置
const newObject = Object.create(null, {name: {value: 'John',writable: true,enumerable: true,configurable: true}
});

修改原型

一般情况下,不需要修改原型对象

/*
不建议通过类的实例去修改原型:因为会通过一个对象影响所有同类对象
*/const  a = new Admin()const a1 = new Admin()const a2 = new Admin()// a、a1、a2对象的set方法都会被修改a.__proto__.set = () => {}a2.__proto__ = new Base() // 不会影响其他对象,相当于是给a2对象赋值了一个新的原型对象

通过prototype修改原型对象

User.proptotype // 访问User实例的原型对象
User.prototype.get = () => {} // 给所有实例添加一个get方法

原型一般不需要修改,如果要修改通过类.prototype去修改

instanceof和hasOwn

// instanceof 用来检查一个对象是否是一个类的实例
// 检查的是对象的原型链上是否有该类实例只要原型链上有该类实例,就会返回true
// Object是所有对象的原型,所以任何和对象和Object进行instanceof运算都会返回trueclass  User {}// 继承Userclass  Admin extends User{name = "l"get(){}set = function (){}}const  admin = new Admin()console.log(admin instanceof Admin) // trueconsole.log(admin instanceof User) // trueconsole.log(admin instanceof Object) // true 

// in用来检查一个对象的自身是否含有某个属性
// 使用in运算符检查属性时,无论属性在对象自身还是在原型中,都会返回true
console.log("get" in admin) // true// 对象.hasOwnProperty检查一个对象的自身是否包含某个属性(不推荐使用)
// hasOwnProperty是在Object原型中的一个方法
console.log(admin.hasOwnProperty("name")) // true
console.log(admin.hasOwnProperty("set")) // true
console.log(admin.hasOwnProperty("get")) // false// Object.hasOwn(对象,属性名) 用来检查一个对象的自身是否含有某个属性(推荐使用)
console.log(Object.hasOwn(admin,"name")) // true
console.log(Object.hasOwn(admin,"set")) // true
console.log(Object.hasOwn(admin,"get")) // false

旧类

早期js中通过函数定义类,如果直接调用就是一个普通函数,通过new调用就是一个构造函数

function User(name){// 在构造函数中,this表示新建的对象this.name = name}// 向原型中添加属性(方法)User.prototype.get = function(){}// 静态属性User.staicName = "a"// 静态方法User.staticGet = function(){}User() // 普通函数const user = new User() // 构造函数

通过旧的方式创建类,方法属性比较分散,可以将其放在一个立即执行函数里面

    var User = (function () {function User(name){// 在构造函数中,this表示新建的对象this.name = name}// 向原型中添加属性(方法)User.prototype.get = function () {}// 静态属性User.staicName = "a"// 静态方法User.staticGet = function () {}const user = new User() // 构造函数// 返回Userreturn User})()const u = new User("l")console.log(u.name)

// 旧类继承  
var User = (function () {function User() {}return User})()var Admin = (function () {function Admin() {}// 继承User,将User对象赋值给Admin的原型Admin.prototype = new User()return Admin})()

new运算符

当使用new 去调用一个函数时,这个函数将会作为构造函数调用

创建一个普通的JS对象(Object对象 {}), 称其为新对象

将构造函数的prototype属性设置为新对象的原型

使用实参来执行构造函数,并且将新对象设置为函数中的this

如果构造函数返回的是一个非原始值,则该值会作为new运算的返回值返回(千万不要这么做)

如果构造函数的返回值是一个原始值或者没有指定返回值,则新的对象将会作为返回值返回

通常不会为构造函数指定返回值

	// 1.创建一个普通的JS对象var newInstance = {}// 2.构造函数的prototype属性设置为新对象的原型newInstance.__proto__ = NewObject.prototype// 3.使用实参来执行构造函数,并且将新对象设置为函数中的thisconstructor() {// 4.如果构造函数返回的是一个非原始值,则该值会作为new运算的返回值返回(千万不要这么做)// 如果构造函数的返回值是一个原始值或者没有指定返回值,则新的对象将会作为返回值返回// 通常不会为构造函数指定返回值}

对象的分类:

1、内建对象

由ES标准所定义的对象

Object Function String Number ....

2、宿主对象

由浏览器提供的对象

BOM、DOM

3、自定义对象

由开发人员自己创建的对象

文章转载自:木子七

原文链接:https://www.cnblogs.com/Mickey-7/p/18467887

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构


http://www.ppmy.cn/embedded/128163.html

相关文章

使用Python解决化学问题的实用指南

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

数据挖掘示例分析

我们想尽量提高利润,为此必须确保橡皮鸭和橡皮鱼的产量都正合适。我们需要您帮忙找出理想的产品组合:这两种产品我们各应该生产多少? 一、市场需求分析 1. 调研市场对橡皮鸭和橡皮鱼的需求情况。了解当前市场上这两种产品的销售量、销售趋势…

基于Matlab使用蚁群算法寻找最优路径

基于Matlab使用蚁群算法寻找最优路径 与Dijkstra算法使用相同的地图。 每只蚂蚁都从起点出发,直到抵达终点。这与Example5_1.m 中解决旅行商问题不一样,旅行商问题中每一代的蚂蚁都是随机从一个节点出发。 文件说明 Example5_1.m 简单对参考资料2中的…

STM32 DMA控制器

目录 STM32 DMA的基本概念 DMA的定义 DMA传输的基本要素 DMA传输过程 DMA的优点与应用 STM32 DMA的结构和主要特征 DMA处理 DMA通道 DMA 中断 DMA的HAL驱动函数 STM32 DMA的基本概念 在很多的实际应用中,有进行大量数据传输的需求,这时如果CP…

UE5 猎户座漂浮小岛 03 视觉效果 粒子

UE5 猎户座漂浮小岛 03 视觉效果 粒子 1.视觉效果 1.1 指数级高度雾 fog指数高度雾组件 0.1、1.4 内颜-淡蓝体雾 1.2 体积光 太阳 directionallight-强度光强-3颜色-淡蓝光束-遮 遮暗-0.018范-10000 1.3 天光 天空照亮,泛光,照大地 skylight强范…

Javascript——html生成并预览 PDF及html导出为Word

html生成并预览 PDF <template><div><div ref"content"><!-- 这里放置你想要转换为 PDF 的 HTML 内容 --><h1>标题</h1><p>这是一些内容。</p></div><button click"exportToPDF">生成并预览 …

R语言绘制聚类热图

聚类热图是一种直观的数据可视化工具。它以矩形彩色图表的形式呈现数据矩阵&#xff0c;每个单元格颜色对应特定数值&#xff0c;通常从低值的冷色调到高值的暖色调渐变。常应用于多个领域&#xff0c;如生物学中分析基因表达、蛋白质相互作用和生物群落&#xff1b;金融领域用…

git gui基本使用

一、图形化界面 二、创建新项目 创建文件&#xff0c;加入暂存区&#xff0c;提交到版本库 三、创建分支 四、合并分支 1.切换至master 五、更新分支 六、解决冲突 修改冲突&#xff0c;加入暂存区&#xff0c;提交到版本库 七、远程创建库 Gitee - 基于 Git 的代码托管和研…