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

9

我正在创建有很多属性的对象,我想知道最佳实践是什么。看起来构造函数过长会很糟糕(实例化新对象不好玩)。

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, ...);

我在想,也许我应该在构造函数中设置三个重要属性(例如标题、作者和页面),并为其余的属性编写单独的setter方法以保持一致性?如果采用这种设置方式是最好的路径,那么在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

最后,将一个对象传递给我的构造函数并解构它,是否完全违背了构造函数的目的?

在构建时,您是否拥有(或需要拥有)创建对象实例之前的所有值?我知道在某些情况下,您希望使用手头已有的信息获取实例,然后从数据源或用户输入中获取其余信息(如果需要)。如果是这种情况,我建议使用生成器模式-请参见此jsfiddle示例:https://jsfiddle.net/brandonscript/p516ojn0/ - blurfus
4个回答

4

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

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 Demo: https://jsfiddle.net/Lr6umykn/3/


3

看起来最好使用一个参数对象和一个混合。这是一把双刃剑,因为它使得实例化对象的代码更易读,但构造函数本身却不那么明显。例如:

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"

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


2

在ES6中,您可以使用解构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中枚举每个属性,只分配有效的参数。

这是否有违首先拥有构造函数的目的?如果这是你的类所做的全部,那么是的。是的。但希望你的类除此之外还有一些方法和目的。


2

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

  1. 使用ES6解构创建你的构造函数:

最初的回答

function Book({reference, publication, author}) {
    this.reference = reference;
    this.publication = publication;
    this.author = author;
}

最初的回答:Instantiation:
翻译后:实例化:
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'
    }
});

最初的回答:
3. 使用方法:
Usage:
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"}

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

原始答案:最初的回答


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接