想品客老师的第十天:类

news2025/2/5 18:41:22

类是一个优化js面向对象的工具

类的声明

        //1、
        class User{}
        console.log(typeof User)//function
        //2、
        let Hd=class{}
        //其实跟1差不多
        class Stu{
            show(){}//注意这里不用加逗号,对象才加逗号
            get(){
                console.log('后盾人')
            }
        }
        let hd=new Stu()
        hd.get()//后盾人

类的原理

类的本质就是个函数,也就相当于【根据这个函数的原型的constructor】

class User{}
console.log(User===User.prototype.constructor)//true

类其实就是个语法糖的结构,意思是确实好用但是你又得背了。。。

类里面直接的、不加任何修饰的内容,都是默认写在原型里的:

class User{show(){console.log('我是个公共属性')
}}
console.dir(User);

类里面有个constructor函数,这个方法的功能是初始化内部的属性,和function里的this.属性名是一个作用:

  class User {
            constructor(name) {
                this.name = name//和下面是一个作用
            }
        }
        // console.log(User === User.prototype.constructor)//true
        console.dir(User);
        function Hd(name) {
            this.name = name//和上面是一个作用
        }
        console.dir(Hd)

对象属性的声明

可以使用简单的this指针改变属性值为传入的形参,也可以用下面这种方法,更灵活:

 class User {
            site = "后盾人";
            constructor(name) {
                this.name = name;
            }
            changeSite(value) {
                this.site = value;
            }
            show() {
                return `${this.site}:${this.name}`;
            }
        }
        let hd = new User("后盾人");
        hd.changeSite("houdunren")//通过内部的方法声明hd对象内部的属性
        console.log(hd.show());

类的遍历

上一篇我们提到了有些方法存在原型中,我们不需要遍历,只能用if (h.hasOwnProperty(key))来解决

而类就可以轻松做到这个,因为class声明的方法不能遍历

   class Hd {
            constructor(name) {
                this.name = name
            }
            show() {
                console.log('我在原型里')

            }
        }
        let h = new Hd()
        for (const key in h) {
            console.log(key)//只打印name,不打印show方法
        }

class默认在严格模式下的运行

这是一般函数在严格模式下的执行:

class Hd {
  show() {
    function test() {
      console.log(this); // 严格模式下,this 是 undefined
    }
    test(); // 直接调用,没有绑定 this
  }
}

let hd = new Hd();
hd.show(); // 在严格模式下,test() 中的 this 是 undefined

而类里面直接就按严格模式执行

class Hd {
      show() {
        function test() {
          console.log(this);
        }
        test();
      }
    }
    let hd = new Hd();
    hd.show();

静态属性的使用

静态成员是就是构造函数或类里的属性和方法,静态属性就是构造函数或类里面的属性

在构造函数里定义静态属性:

  function Web(url) {
            this.url = url;
        }
        Web.url = "hdcms.com";
        let hd = new Web("houdunren.com");
        console.log(hd);
        console.dir(Web);

在类里面设置静态属性

class Request {
      static host = "https://www.houdunren.com";
      api(url) {
        return Request.host + `/${url}`;
      }
    }
    let obj = new Request();
    console.log(obj.api("article"));

像这种不改变的静态地址,最好前面加上static

静态方法的实现原理

在类中使用访问器

前面学过访问器,这是访问器在类的使用:

   class Request {
            constructor(host) {
                this.data = {}
                this.host = host
            }
            set host(url) {
                if (!/^https:?\/\//i.test(url)) {
                    throw new Error('地址错误')
                }
                this.data.host = url
            }
            get host() {
                return this.data['host']
            }
        }
        let hd = new Request('https://houdunren.com')

属性保护

用命名原则保护属性

意思就是约定俗成的【下划线开头的】属性就是私有属性

 class User {
      _url = "https://houdunren.com";//被保护的,外部访问不了
      constructor(name) {
        this.name = name;
      }
      set url(url) {//但是url可以访问
        if (!/^https?:/i.test(url)) {
          throw new Error("非常网址");
        }
        this._url = url;
      }
    }
    let hd = new User("后盾人");
    hd.name = "李四";
    hd.url = "https://hdcms.com";//所以通过url改变_url
    console.log(hd);

使用Symbol定义protected属性

关于symbol可以保护数据这里之前在对象学过类似的概念,但是我没懂:

如果想保存的话可以把属性定为私有属性,symbol可以让他变成私有属性

"use strict";
    const DATA = Symbol();
    const user = {
      // name: "后盾人",
      [DATA]: { name },
      age: 10,
      set name(value) {
        this[DATA].name = value;
      },
      get name() {
        return this[DATA].name;
      }
    };
    user.name = "hdcms";
    // user.data.name = "你好";
    console.log(user[Symbol()])

那你就要问了:symbol和私有属性什么关系,为啥symbol可以防止被修改?

deepseek太卡了,我们有请老朋友chatgpt作答:

Symbol 本身并没有提供不可修改(immutable)功能。它只是保证了每个 Symbol 是唯一的,也就是说它保证了属性键的唯一性,而不是数据本身的不可修改性。
但是,使用 Symbol 作为属性键可以间接达到“数据隐私”和“不可直接访问”的目的,因为 Symbol 属性不容易被外部直接修改。
怎么间接达到的?因为我们无法通过常规的方式来访问symbol定义的属性名的属性了:

const DATA = Symbol("privateData"); // 创建一个唯一的 Symbol
const user = {
  [DATA]: { name: "Alice", age: 25 }, // 用 Symbol 创建私有数据
  get name() {
    return this[DATA].name;
  },
  set name(value) {
    this[DATA].name = value;
  }
};
 
console.log(user.name);  // "Alice"
user.name = "Bob";       // 调用 setter
console.log(user.name);  // "Bob"
 
// 但是我们不能直接访问或修改 [DATA] 属性
console.log(user[DATA]); // undefined

在这个例子中,[DATA] 是一个私有的 Symbol 属性。虽然你可以通过 name 的 getter 和 setter 修改 name,但是无法直接通过 user[DATA] 来访问或修改 name。这是因为 Symbol 提供了 唯一性,使得你无法直接通过常规方式访问这个属性。

这样就只能用访问器修改数据了?了吗??

 "use strict";
            const DATA = Symbol();
            const user = {
                // name: "后盾人",
                [DATA]: { name },
                age: 10,
                set name(value) {
                    this[DATA].name = value;
                },
                get name() {
                    return this[DATA].name;
                }
            };
            //user.name = "hdcms";
            user[DATA].name='荷叶饭'
            console.log(user[DATA])

可是我这么写的时候修改成功了啊?后盾人你在说什么?

 const protecteds = Symbol();
    class Common {
      constructor() {
        this[protecteds] = {};
        this[protecteds].host = "https://houdunren.com";
      }
      set host(url) {
        if (!/^https?:/i.test(url)) {
          throw new Error("非常网址");
        }
        this[protecteds].host = url;
      }
      get host() {
        return this[protecteds].host;
      }
    }
    class User extends Common {
      constructor(name) {
        super();
        this[protecteds].name = name;
      }
      get name() {
        return this[protecteds].name;
      }
    }
    let hd = new User("后盾人");
    hd.host = "https://www.hdcms.com";
    console.log(hd.name);

使用WeakMap保护属性

卧槽电脑坏了学不进去

 const protecteds = new WeakMap();
    class Comment {
      constructor() {
        protecteds.set(this, {
          host: '"https://houdunren.com"'
        });
      }
      set host(url) {
        if (!/^https?:/i.test(url)) {
          throw new Error("非常网址");
        }
        protecteds.set(this, { ...protecteds.get(this), url });
      }
      get host() {
        return protecteds.get(this)["host"];
      }
    }
    class User extends Comment {
      constructor(name) {
        super();
        this.name = name;
      }
      set name(name) {
        protecteds.set(this, { ...protecteds.get(this), name });
      }
      get name() {
        return protecteds.get(this)["name"];
      }
    }
    let hd = new User("后盾人");
    // hd.name = "向军";
    // console.log(hd.name);
    console.log(hd);

草泥马七彩虹我草泥马

鸡肉和巴豆,这篇学不下去换个学去了

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

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

相关文章

MyBatis-Plus速成指南:条件构造器和常用接口

Wrapper 介绍 Wrapper:条件构造抽象类,最顶端父类 AbstractWrapper:用于查询条件封装,生成 SQL 的 where 条件QueryWrapper:查询条件封装UpdateWrapper:Update 条件封装AbstractLambdaWrapper:使…

(脚本学习)BUU18 [CISCN2019 华北赛区 Day2 Web1]Hack World1

自用 题目 考虑是不是布尔盲注,如何测试:用"1^1^11 1^0^10,就像是真真真等于真,真假真等于假"这个测试 SQL布尔盲注脚本1 import requestsurl "http://8e4a9bf2-c055-4680-91fd-5b969ebc209e.node5.buuoj.cn…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.25 多线程并行:GIL绕过与真正并发

2.25 多线程并行:GIL绕过与真正并发 目录 #mermaid-svg-JO4lsTIyjOweVkos {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-JO4lsTIyjOweVkos .error-icon{fill:#552222;}#mermaid-svg-JO4lsTIyjOweVkos …

Java 大视界 -- Java 大数据在智能医疗影像诊断中的应用(72)

💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也期待你毫无保留地分享独特见解,愿我们于此携手成长,共赴新程!💖 一、…

【Leetcode刷题记录】1456. 定长子串中元音的最大数目---定长滑动窗口即解题思路总结

1456. 定长子串中元音的最大数目 给你字符串 s 和整数 k 。请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。 英文中的 元音字母 为(a, e, i, o, u)。 这道题的暴力求解的思路是通过遍历字符串 s 的每一个长度为 k 的子串&#xf…

upload-labs安装与配置

前言 作者进行upload-labs靶场练习时,在环境上出了很多问题,吃了很多苦头,甚至改了很多配置也没有成功。 upload-labs很多操作都是旧时代的产物了,配置普遍都比较老,比如PHP版本用5.2.17(还有中间件等&am…

从Transformer到世界模型:AGI核心架构演进

文章目录 引言:架构革命推动AGI进化一、Transformer:重新定义序列建模1.1 注意力机制的革命性突破1.2 从NLP到跨模态演进1.3 规模扩展的黄金定律二、通向世界模型的关键跃迁2.1 从语言模型到认知架构2.2 世界模型的核心特征2.3 混合架构的突破三、构建世界模型的技术路径3.1 …

每日一博 - 三高系统架构设计:高性能、高并发、高可用性解析

文章目录 引言一、高性能篇1.1 高性能的核心意义1.2 影响系统性能的因素1.3 高性能优化方法论1.3.1 读优化:缓存与数据库的结合1.3.2 写优化:异步化处理 1.4 高性能优化实践1.4.1 本地缓存 vs 分布式缓存1.4.2 数据库优化 二、高并发篇2.1 高并发的核心意…

【工欲善其事】利用 DeepSeek 实现复杂 Git 操作:从原项目剥离出子版本树并同步到新的代码库中

文章目录 利用 DeepSeek 实现复杂 Git 操作1 背景介绍2 需求描述3 思路分析4 实现过程4.1 第一次需求确认4.2 第二次需求确认4.3 第三次需求确认4.4 V3 模型:中间结果的处理4.5 方案验证,首战告捷 5 总结复盘 利用 DeepSeek 实现复杂 Git 操作 1 背景介绍…

【C++】线程池实现

目录 一、线程池简介线程池的核心组件实现步骤 二、C11实现线程池源码 三、线程池源码解析1. 成员变量2. 构造函数2.1 线程初始化2.2 工作线程逻辑 3. 任务提交(enqueue方法)3.1 方法签名3.2 任务封装3.3 任务入队 4. 析构函数4.1 停机控制 5. 关键技术点解析5.1 完美转发实现5…

数据结构实战之线性表(三)

目录 1.顺序表释放 2.顺序表增加空间 3.合并顺序表 4.线性表之链表实现 1.项目结构以及初始代码 2.初始化链表(不带头结点) 3.链表尾部插入数据并显示 4.链表头部插入数据 5.初始化链表(带头结点) 6.带头结点的链表头部插入数据并显示 7.带头结…

【python】python基于机器学习与数据分析的手机特性关联与分类预测(源码+数据集)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉专__注👈:专注主流机器人、人工智能等相关领域的开发、测试技术。 python基于机器学习与数据分析的手机特性关联与分类…

ZOJ 1007 Numerical Summation of a Series

原题目链接 生成该系列值的表格 对于x 的 2001 个值,x 0.000、0.001、0.002、…、2.000。表中的所有条目的绝对误差必须小于 0.5e-12(精度为 12 位)。此问题基于 Hamming (1962) 的一个问题,当时的大型机按今天的微型计算机标准来…

全面解析文件上传下载删除漏洞:风险与应对

在数字化转型的时代,文件上传、下载与删除功能已经成为各类应用程序的标准配置,从日常办公使用的协同平台,到云端存储服务,再到社交网络应用,这些功能在给用户带来便捷体验、显著提升工作效率的同时,也隐藏…

【C语言深入探索】结构体详解(二):使用场景

目录 一、复杂数据的表示 二、数据的封装 三、多态的模拟 四、回调函数的实现 五、多线程编程 六、通信协议的实现和文件操作 6.1. 使用结构体实现简单通信协议 6.2. 使用结构体进行文件操作 七、图形界面编程 结构体在C语言中具有广泛的应用场景,以下是一…

【大模型】AI 辅助编程操作实战使用详解

目录 一、前言 二、AI 编程介绍 2.1 AI 编程是什么 2.1.1 为什么需要AI辅助编程 2.2 AI 编程主要特点 2.3 AI编程底层核心技术 2.4 AI 编程核心应用场景 三、AI 代码辅助编程解决方案 3.1 AI 大模型平台 3.1.1 AI大模型平台代码生成优缺点 3.2 AI 编码插件 3.3 AI 编…

RK3566-移植5.10内核Ubuntu22.04

说明 记录了本人使用泰山派(RK3566)作为平台并且成功移植5.10.160版本kernel和ubuntu22.04,并且成功配置&连接网络的完整过程。 本文章所用ubuntu下载地址:ubuntu-cdimage-ubuntu-base-releases-22.04-release安装包下载_开源…

从零开始实现一个双向循环链表:C语言实战

文章目录 1链表的再次介绍2为什么选择双向循环链表?3代码实现:从初始化到销毁1. 定义链表节点2. 初始化链表3. 插入和删除节点4. 链表的其他操作5. 打印链表和判断链表是否为空6. 销毁链表 4测试代码5链表种类介绍6链表与顺序表的区别7存储金字塔L0: 寄存…

51单片机 06 定时器

51 单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成。 作用:1、用于计时;2、替代长时间的Delay,提高CPU 运行效率和处理速度。 定时器个数:3个(T0、T1、T2)&#xf…

【C++】P1957 口算练习题

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯题目描述输入格式:输出格式: 💯我的做法代码实现: 💯老师的做法代码实现: 💯对比分析&am…