请你设计一下ES6中 class 类实现私有属性

为什么会出现class


 其实,学过 java 的小伙伴一定对 class 熟悉不过了。那为什么 JS 里面还要引入 class 呢?

es6 之前,虽然 JSJava 同样都是 OOP (面向对象)语言,但是在 JS 中,只有对象而没有类的概念。

es6 中 class 的出现拉近了 JS 和传统 OOP 语言的距离。但是,它仅仅是一个语法糖罢了,不能实现传统 OOP 语言一样的功能。在其中,比较大的一个痛点就是私有属性问题。

何为私有属性?

  私有属性是面向对象编程(OOP)中非常常见的一个特性,一般满足以下的特点:

  1:  能被class类内部的不同方法访问,但是不能在类外部被访问

   2: 子类步能继承父类的私有属性

在 Java 中,可以使用 private 实现私有变量,但是可惜的是, JS 中并没有该功能。 

私有属性提案 


 在2015年6月,ES6正式成为标准,为了纪念这个时刻,这个标准又被称为ES2015。

javaScript 中的 class 从备胎中转正,但是没有解决私有属性的问题,产生了一个提案------在属性名前加上  #   ,就表示是一个私有属性。

class Foo {
  #a;  // 定义私有属性
  constructor(a, b) {
    this.#a = a;
    this.b = b
  }
}

备注: 上述代码私有属性的声明,需要先经过Babel等编译器编译后才能正常使用

至于为什么不用 private 关键字呢?参考大佬说的就是有一大原因是向 Python 靠拢,毕竟从 es6 以来, JS 一直向着 Python 发展。

如何设计实现私有属性呢?


 上文我们介绍了class类 出现原因,以及它没有解决私有属性这个问题,那么如何自己设计一下呢?带着好奇心来探讨一下吧

class Student {
  constructor(name, age) {
    this._name = name;
    this._age = age;
  }
  get userInfo() {
    return '姓名:' + this._name + ',年龄:' + this._age;
  }
}

const handler = {
  get: function (target, key) {
    if (key[0] === '_') { // 访问私有属性,返回一个 error
      throw new Error('Attempt to access private property');
    } else if (key === 'toJSON') {
      const obj = {};
      for (const key in target) { // 只返回公共属性
        if (key[0] !== '_') {
          obj[key] = target[key];
        }
      }
      return () => obj;
    }
    return target[key]; // 访问公共属性,默认返回
  },
  set: function (target, key, value) {
    if (key[0] === '_') {
      throw new Error('Attempt to access private property');
    }
    target[key] = value;
  },
  // 解决私有属性能遍历问题,通过访问属性对应的属性描述符,然后设置 enumerable 为 false
  getOwnPropertyDescriptor(target, key) {
    const desc = Object.getOwnPropertyDescriptor(target, key);
    if (key[0] === '_') {
      desc.enumerable = false;
    }
    return desc;
  }
}

const stu = new Proxy(new Student('Chocolate', 21), handler);

console.log(stu.userInfo);           // 姓名:Chocolate,年龄:21
console.log(stu instanceof Student); // true
console.log(JSON.stringify(stu));  // "{}"
for (const key in stu) {           // No output 不能遍历私有属性
  console.log(key);
}
stu._name = 'Lionkk';                  // Error: Attempt to access private property

新式做法

就发展趋势来看, TS 已经成为前端必备的技能之一,TypeScript 的 private 很好解决了私有属性这个问题,后续学习了 ts 之后再补充吧。

附:TypeScript 中的处理方式

TypeScript 是 JavaScript 的一个超集,它会编译为原生 JavaScript 用在生产环境。允许指定私有的、公共的或受保护的属性是 TypeScript 的特性之一。

class Student {
  private name;
  private age;

  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  get userInfo() {
    return '姓名:' + this.name + ',年龄:' + this.age;
  }
}

const stu = new Student('Chocolate', 21);
console.log(stu.userInfo);           // 姓名:Chocolate,年龄:21

使用 TypeScript 需要注意的重要一点是,它只有在 编译 时才获知这些类型,而私有、公共修饰符在编译时才有效果。

如果你尝试访问 stu.name,你会发现,居然是可以的。

只不过 TypeScript 会在编译时给你报出一个错误,但不会停止它的编译。

// 编译时错误:属性 ‘name’ 是私有的,只能在 ‘Student ’ 类中访问。
console.log(stu.name); // 'Chocolate'

TypeScript 不会自作聪明,不会做任何的事情来尝试阻止代码在运行时访问私有属性。我只把它列在这里,也是让大家意识到它并不能直接解决问题。

另外,TypeScript 的 class 私有变量最终编译也是通过 WeakMap 来实现的,来自评论区小伙伴们的解答~

 

https://juejin.cn/post/6881894768117284878

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值