4

这些功能是如何运作的?第一个更典型的是我在考虑构造函数时考虑的内容。使用构造函数创建对象与返回对象有区别吗?

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

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

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

实施例2:通过使用,只是调用函数本身返回一个对象。

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

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

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

我想我试图找出是,如果这些都是他们创造的对象的方式有什么不同?如果是这样一个比另一个更好?是否有不同的情况下,一个会比另一个更好地工作?

+2

返回一个文字不会通过构造函数上的'.prototype'支持继承。如果你想继承,使用“new”+构造函数。如果没有,请使用工厂,如第二代码。 – dandavis

+2

在你的第二个片段中,'new'被忽略。不必要地创建从“Movie.prototype”继承的空对象。只是不要在工厂功能中使用'new'。不,他们不一样。 – Bergi

+0

你不应该使用第二个。你不再从Movie.prototype继承,它是例如'other/best instanceof Movie //返回false'。我建议你阅读这个:https://zetafleet.com/blog/2014/12/back-to-basics-javascript-functions-constructors-and-this-demystified.html#ref-5 – Kiechlus

回答

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等。最后,这都是偏好问题。

2

第一个是构造函数,因此可以通过prototype进行扩展,并且可以通过instanceof进行测试,结果就是这种类型的实例。 缺点:当你忘记了new -keyword您的代码将炸毁(除非你写一个解决办法到每个constuctor

而且你不能真正使用apply()一个构造函数传递参数数组,你实例化一个新的Object;另一方面,即使你能/可以,也不要那样做。

第二个是工厂,而不是构造函数。是否使用new关键字是否独立。 在此实现中,它创建的对象看起来相同,但不共享类型或原型(尽管底层JS引擎将它们识别为相似,因此它们共享相同的隐藏类,只要它们具有相同的属性,即可添加相同的顺序,...不同的主题)
长话短说,无论是性能还是内存占用这一办法(再)

遭受但是你不能检查它们是否是同一类型的,和你没有共享原型,可能会影响所有实例(可能是专业人士或con。)

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

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" 
}); 

如果我下面的行添加到该函数的顶部我还可以使用它作为一种方法来投什么成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); 

在我看来,我用这种方法得到了两个世界的好处。

0

区别在于用于创建返回对象的构造函数。

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

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

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

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

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

相关问题