当前位置: 首页 > article >正文

想品客老师的第天:类

类是一个优化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);


http://www.kler.cn/a/530097.html

相关文章:

  • linux本地部署deepseek-R1模型
  • 基于springboot+vue的哈利波特书影音互动科普网站
  • HTML5 技术深度解读:本地存储与地理定位的最佳实践
  • 面试问题知识
  • 【网络】传输层协议TCP(重点)
  • 【LLM-agent】(task4)搜索引擎Agent
  • Java集合+并发(部分)
  • MultiResUNet学习笔记(2019 Neural Networks【SCI 1区】)
  • 用结构加法3ax+1预测第4点的分布
  • 掌握Spring MVC异常处理的艺术
  • ICLR 2025收录论文:为什么动作分块对于机器人灵活性至关重要?
  • makailio-alias_db模块详解
  • 蓝桥杯备考:六大排序算法
  • Hive重点面试题
  • #define,源文件与头文件,赋值表达式
  • Java项目: 基于SpringBoot+mybatis+maven+mysql实现的疾病防控综合管理系统(含源码+数据库+毕业论文)
  • springboot中路径默认配置与重定向/转发所存在的域对象
  • react注意事项
  • 6 [新一代Github投毒针对网络安全人员钓鱼]
  • 【JDBC】数据库连接的艺术:深入解析数据库连接池、Apache-DBUtils与BasicDAO
  • 双指针算法思想——OJ例题扩展算法解析思路
  • 悬浮按钮和可交互提示的使用
  • 设计数据库表会考虑哪些内容?
  • 文字投影效果
  • C++ Primer 命名空间的using声明
  • 2025最新在线模型转换工具onnx转换ncnn,mnn,tengine等