JavaScript 中长构造函数的最佳实践

Posted

技术标签:

【中文标题】JavaScript 中长构造函数的最佳实践【英文标题】:Best Practices for Long Constructors in JavaScript 【发布时间】:2017-09-13 09:14:53 【问题描述】:

我正在创建具有许多属性的对象,我对实例化它们的最佳实践感到好奇。拥有很长的构造函数似乎很糟糕(实例化新对象并不好玩)。

function Book(title, author, pages, chapters, publisher, datePublished, authorHometown, protagonistFavoriteColor) 
  this.title = title;
  this.authorpages = authorpages;
  this.pages = pages;
  this.chapters = chapters;
  this.publisher = publisher;
  this.datePublished = datePublished;
  this.authorHometown = authorHometown;
  this.protagonistFavoriteColor = protagonistFavoriteColor;


// not reliable to remember how to order params
var rc = new Book("Robinson Crusoe", "Daniel Defoe", 342, 16, ...);

我想知道我是否应该在构造函数中设置三个重要的属性(例如标题、作者和页面),然后为其余部分编写单独的设置器。或者为了保持一致性,我应该只使用二传手吗?如果设置这种方式是最好的方法,那么 JS 中是否有一种好方法可以强制调用这些方法(有点像 Java 中的接口)?

function Book (title, author, pages)
  this.title = title;
  this.author = author;
  this.pages = pages;
  this.chapters = null;
  this.publisher = null;
  this.datePublished = null;
  this.authorHometown = null;
  this.protagonistFavoriteColor = null;


var rc = new Book("Robinson Crusoe", "Daniel Defoe", 342);
rc.setChapters(16);
rc.setPublisher("John Smith Co.");
rc.setDatePublished("04-25-1719");
rc.setAuthorHometown("London");
rc.setProtagonistFavoriteColor("lilac");
// we'd also want to mandate that these setters be called so nothing is left null

最后,将一个对象传递给我的构造函数并对其进行解构会完全破坏构造函数的 pt 吗?

【问题讨论】:

在构建时,在创建对象的实例之前,您是否拥有(或需要拥有)所有值? - 我知道在某些情况下,您希望使用手头的信息获取实例,然后从数据源或用户输入中获取其余信息(如果需要)。如果是这种情况,我建议使用构建器模式 - 以这个小提琴为例:jsfiddle.net/brandonscript/p516ojn0 【参考方案1】:

最佳实践是将定义属性的对象传递给构造函数:

function Book(props) 
  // create variables out of object (if you need to)
  const 
    title,
    author,
    pages,
    chapters,
    publisher,
    datePublished,
    authorHometown,
    protagonistFavoriteColor
   = props;

  // assign properties to instance object
  Object.assign(this, props);


const rc = new Book(
  title: "Robinson Crusoe",
  author: "Daniel Defoe",
  pages: 342,
  chapters: 16,
  // rest of properties
);

console.log(rc);

JSFiddle 演示:https://jsfiddle.net/Lr6umykn/3/

【讨论】:

【参考方案2】:

似乎最好使用 arguments 对象和 mixin。这是一把双刃剑,因为它使实例化对象的代码更易于阅读,但构造函数本身就不那么明显了。例如

function Book(args) 
     Object.assign(this, args);


var rc = new Book(
    name:   "Robinson Crusoe",
    author: "Daniel Defoe",
    pages:  342
);

如果你想要默认值,那么你可以用另一个 mixin 来实现它,例如

function Book(args) 
    args = Object.assign(args, 
       protagonistFavoriteColor: "Red"
    );

    Object.assign(this, args);
 

然后是一个调用,例如:

var rc = new Book(
    name:   "Robinson Crusoe",
    author: "Daniel Defoe",
    pages:  342
);

愿意:

rc.author; // "Daniel Defoe"
rc.protagonistFavoriteColor // "Red"

如果您想确保提供了某些值,则需要在构造函数的末尾测试这些值是否存在并抛出错误。

【讨论】:

【参考方案3】:

在 es6 中,您可以使用 destructuring 和 Object.assign 来简化复制构造函数模式(构造函数将带参数的对象作为其单个参数):

function Book(title, author, pages, chapters, publisher, datePublished,
               authorHometown, protagonistFavoriteColor) 
  Object.assign(this, title, author, pages, chapters, publisher, datePublished,
                       authorHometown, protagonistFavoriteColor);


var rc = new Book(title: "Robinson Crusoe", author: "Daniel Defoe",
                   pages: 342, chapters: 16);

var copy = new Book(rc);

console.log(JSON.stringify(rc));
console.log(JSON.stringify(copy));
console.log(copy == rc); // false

之所以这样称呼,是因为您现在可以方便地从另一个实例创建对象。

我们枚举Object.assign中的每个属性,只分配有效参数。

这是否违背了首先拥有构造函数的目的?如果这就是你班级所做的一切,那么是的。是的,它确实。但希望您的课程除此之外还有一些方法和目的。

【讨论】:

【参考方案4】:

我知道这是一个古老的要求,但我想知道为什么没有人提到复杂的对象。在我看来,这是组织和存储数据的最简单方法。

    使用 ES6 解构创建您的构造函数:
function Book(reference, publication, author) 
    this.reference = reference;
    this.publication = publication;
    this.author = author;

    实例化:
var rc = new Book(
    reference: 
        title: 'Robinson Crusoe',
        pages: 342,
        chapters: 16,
        protagonistFavoriteColor: 'lilac'
    ,
    publication: 
        publisher: 'John Smith co.',
        date: '04-25-1719'
    ,
    author: 
        name: 'Daniel Defoe',
        homeTown: 'London'
    
);
    用法:
console.log(rc.reference.title); // 'Robinson Crusoe'
console.log(rc.publication.date); // '04-25-1719'
console.log(rc.author.name); // 'Daniel Defoe'

此方法还使您可以访问整个类别。

console.log(rc.author); // name: "Daniel Defoe", homeTown: "London"

console.log(rc.reference); // title: "Robinson Crusoe", pages: 342, chapters: 16, protagonistFavoriteColor: "lilac"

熟悉了这个组织之后,创建对象就变得简单而有趣了。

【讨论】:

以上是关于JavaScript 中长构造函数的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

构造函数重载 - Java 中的最佳实践 [关闭]

base() 和 this() 构造函数最佳实践

Javascript 在这种情况下使用 IF 或 SWITCH 或“动态函数名”的最佳实践是啥

javascript之小积累-匿名函数表达式的最佳实践

Javascript、视图和事件最佳实践

初始化List的最佳做法?自动装配列表或构造函数初始化?