工厂内的原型分配,以实现私有字段处理与没有原型方法的构造函数和私有状态

问题描述 投票:0回答:1

我知道有很多关于模块模式、原型继承、ES6 类等的问题,并且都有很好的答案。这不是讨论不同的模式或 ES6 类的缺点。 我的问题是关于两种具体方法的区别和优缺点,在现有问题中我找不到明确的答案。

我喜欢模块模式带来的灵活性,并且我完全理解依赖原型链的陷阱、限制和缺点(无论是否使用

class

关键字或带有原型的传统函数)。但是,我希望(有时需要)我创建的对象可以通过

instanceof
“识别”。
我知道两种方法结合模块模式(以及进行对象组合的能力),同时将对象的原型与创建它的函数联系起来。

方法一:类似模块模式,但是我们手动设置返回对象的原型

function Bar() { let privateVar = 1; const someMethod = () => { // do something }; return Object.setPrototypeOf({ someMethod }, Bar.prototype); } const b = new Bar() // can omit new as well console.log(b, b instanceof Bar); // gets a nice "Bar" name in the console + instanceof true

方法2:包装类并在构造函数中分配所有方法

class Foo { constructor() { let privateVar = 1 this.someMethod = () => { // do something } } } const f = new Foo() // must call with new console.log(f, f instanceof Foo); // same as Method 1

问题

这两种方法都有缺点吗?明显是好是坏。或者它们都不好,因为它们违反了类或构造函数可以“扩展”的期望,并且人们期望在原型上找到属性/方法?

javascript constructor factory prototypal-inheritance private-members
1个回答
1
投票
它们都违反了类或构造函数可以“扩展”的期望吗?

不。只有您的第一个片段不支持子类化,因为它确实将原型硬编码为
Bar.prototype

。编写此代码的通常方法是仍然在构造函数中使用

this
function Bar() {
  let privateVar = 1;
  this.someMethod = () => {
    // do something
  };
}

如果您想处理呼叫者忘记 
new

关键字的情况,有多种方法可以解决此问题:

function Bar() {
  if (!(new.target && this instanceof Bar)) throw new Error('Invalid call');
  let privateVar = 1;
  this.someMethod = () => {
    // do something
  };
}
function Bar() {
  let privateVar = 1;
  const someMethod = () => {
    // do something
  };
  if (new.target) {
    this.someMethod = someMethod;
  } else {
    return { __proto__: Bar.prototype, someMethod };
  }
}
function Bar() {
  const self = new.target ? this : { __proto__: Bar.prototype };
  let privateVar = 1;
  self.someMethod = () => {
    // do something
  };
  return self;
}

从人们期望在原型上找到属性/方法的意义上来说,它们都是不好的吗?

是的,但实际上这不再是普遍预期的。有很多代码在实例上创建函数值自己的属性(使用 ES5 风格、ES6
class

语法或 ES2022 类字段),无论是用于创建绑定方法还是私有状态上的闭包还是其他。

如果您在文档中指出这一点,以及子类应满足的契约期望,将会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.