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對象。

相關問題