为什么 MDN 说原型继承中不能有私有属性?

MDN 说私有属性是原型继承中没有简单替代方案的特性:

image.png

可是不是能用闭包写私有属性吗:

function C() {
  // 私有属性
  let value = 0;

  Object.defineProperty(this, "v", {
    get: () => value,
    set: (v: number) => value = v,
  });
}

es6 类写法:

class C2 {
  #value = 0;

  get v() {
    return this.#value;
  }
  set v(v) {
    this.#value = v;
  }
}

这两种写法有什么区别吗?

阅读 964
avatarAI BotBETA

MDN 文档中关于原型继承中不能有私有属性的说法并不准确。实际上,JavaScript 中的类(自 ES6 引入)提供了私有属性的特性。这主要是通过 # 前缀来达成的,它表示一个属性是私有的,即只能在类的内部访问。

在你提供的例子中,C2 类的 #value 就是一个私有属性。只有在 C2 内部,或者继承自 C2 的类中,才能访问到这个属性。从外部是无法直接访问这个属性的,尝试访问会抛出一个错误。

而你的第一个例子中,value 并不是真正的私有属性。它只是一个用 getter 和 setter 方法模拟的私有属性。这种方法并不能阻止外部代码直接访问或修改这个属性。例如,如果我知道这个 getter 和 setter 的实现,我可以直接调用 Object.defineProperty 来修改或删除这个属性。

因此,虽然 JavaScript 的原型继承中确实不支持真正的私有属性,但 ES6 类提供了私有属性的特性,这是一个很重要的区别。这种特性可以提供更好的封装性和安全性,是面向对象编程的一个重要特性。

1 个回答

MDN 的作者措辞还是非常严谨的,“简单替代方案”,也就是说实现类似的功能,道路将会非常曲折。
你的方法已经略显曲折了,但还是没有完全模拟出私有属性该有的样子——如果使用原型链继承的话,所有子类实例的 .v 属性都会指向同一个 value

function SubC (){}
SubC.prototype = new C();

var subC1 = new SubC();
var subC2 = new SubC();

// 注意这里修改的是 subC1.v
subC1.v = 10086;

// 注意这里打印的是“没被修改”的 subC2.v
console.log(subC2.v) // 10086

不过,这并不是你的写法有问题,而是原型链继承的固有缺陷,所以这里要被迫使用构造函数继承,这就偏离了“原型链继承”的语境限制,复杂程度也更上一层楼:

function SubC1 (){
  C.call(this);
}
SubC.prototype = new C();
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题