4

这些功能的运作方式有什么不同吗?第一个更典型的是我在考虑构造函数时的想法。

示例 1:使用来命名和设置属性。然后使用 new 创建一个新的 Book 对象。

    function Book(name, numPages) {
        this.name = name;
        this.numPages = numPages;
    }

    var myBook = new Book('A Good Book', '500 pages');

示例 2:使用new返回一个对象,只调用函数本身。

    function Movie(name, numMinutes) {
        return { name:name, numMinutes:numMinutes };
    }

    var best = new Movie('Forrest Gump', '150');

    var other = Movie('Gladiator', '180');

我想我想弄清楚的是它们创建对象的方式是否不同?如果是这样,一个比另一个更好吗?是否存在不同的情况,其中一种会比另一种更好?

4

3 回答 3

2

第一个是构造函数,因此可以通过 a 扩展prototype,您可以通过instanceof结果是否是这种类型的 Instance 进行测试。缺点:如果您忘记了new-keyword,您的代码将会崩溃(除非您为 each 编写解决方法constuctor

当你实例化一个新对象时,你不能真正使用apply()构造函数来传递参数数组;另一方面,不要那样做,即使你可以/可以。

第二个是工厂,而不是构造函数。无论您是否使用new-keyword 都是独立的。通过这个实现,它创建了看起来相同但不共享类型或原型的对象(尽管底层 JS 引擎将它们识别为相似,因此只要它们具有相同的属性,它们就共享相同的隐藏类,添加到相同的顺序,......不同的主题)
长话短说,性能和内存占用都不会受到这种方法的影响(不再)

但是您无法检查它们是否属于同一类型,并且您没有可能影响所有实例的共享原型(可能是赞成或反对)。

我的 goto 方法如果我需要继承,是两者的混合:(
如果我只需要一个数据对象,我通常使用工厂和普通对象)。

function Book(conf) {
    var book = Object.create(Book.prototype);
    //a book like this usually has multiple configs/properties
    if(typeof conf === "object"){
        for(var k in conf) book[k] = conf[k];
    }else if(conf){
        //assuming that I get at least the name passed
        book.name = String(conf);
    }
    return book;
}

//I have a prototype that can be extended
//with default-values for example; no idea for a good method 
//to add to the prototype in this example ;)
Book.prototype.numPages = 0;

//but I can also use it like a plain function; no error if you 
var myBook1 = Book("Peter Pan");
var myBook2 = Book({
    name: "American Gods",
    author: "Neil Gaiman"
});

如果我将以下行添加到函数的顶部,我还可以将其用作将任何内容转换为 Instance 的方法,Book而无需克隆已经存在的实例

function Book(conf) {
    //with this simple line I can also use this as a function to cast anything into a "Book"
    if(conf instanceof Book) return conf;

    var book = Object.create(Book.prototype);
    //...
    return book;
}

var data = [
    "Peter Pan",
    {name: "American Gods"},
    //...
];

var books = data.map(Book);

在我看来,我通过这种方法获得了两全其美的好处。

于 2016-04-04T22:58:22.743 回答
0

基本上,当您使用 时new,JS 引擎会为您创建一个全新的对象并将其作为this. 它还自动为您提供附加到构造函数原型的任何方法。使用构造函数还可以让您更轻松地检查对象是否是instanceof某物。

function MovieA(title) {
    this.title = title;
}
MovieA.prototype.getTitle = function() {
    return this.title;
};

function MovieB(title) {
    return {
    title: title
  };
}
MovieB.prototype.getTitle = function() {
    return this.title;
};

var a = new MovieA('A');
console.log(a instanceof MovieA); // true
console.log(a.getTitle()); // 'A'

var b = MovieB('B');
console.log(b instanceof MovieB); // false
console.log(b.getTitle()); // Uncaught TypeError: b.getTitle is not a function

提供给您的一切都new可以通过其他方法获得,但需要更多的体力劳动。

第二种方法,工厂,往往更适合单元测试、自定义对象创建和函数式编程。它更适合单元测试,因为如果你有一个生产所有对象的工厂,你可以用一个模型替换那个工厂来测试不同的案例。

var Factory = {
  makeThing: function() {
    return { name: 'thing' };
  }
};

// Want to test the case for if makeThing fails inside of some other code
var MockFactory = {
  makeThing: function() {
    return null;
  };
};

至于你什么时候使用,这一切都取决于。有些人根本不用new。其他人专门使用new. 这完全取决于您是否需要上面列出的任何东西,您需要对对象的创建进行多少控制,何时要使用this或不使用等等。最后,这完全取决于偏好。

于 2016-04-04T22:29:10.960 回答
0

不同之处在于用于创建返回对象的构造函数。

new Book('A Good Book', '500 pages');

创建一个Book对象实例,该实例继承自 的属性Book.prototype,包括 的constructor属性值BookBook.prototype对象本身继承自Object.prototype.

var other = Movie('Gladiator', '180');

用作Movie工厂函数(new非必需)并返回一个 Object 对象实例,该实例直接从 继承属性Object.prototype,包括 的constructor属性值Object

更简单地说,Object 字面量语法创建一个 Object 对象。

于 2016-04-04T23:28:11.177 回答