2015-03-02 43 views
1

我知道,我們可以通過以下方法創建新的函數實例。但我的問題是否有其他方法可以實現?Javascript - 如何創建函數的新實例

var Person = function (firstName) { 
    this.firstName = firstName; 
    console.log('Person instantiated'); 
}; 

var person1 = new Person('Alice'); 
var person2 = new Person('Bob'); 

// Show the firstName properties of the objects 
console.log('person1 is ' + person1.firstName); // logs "person1 is Alice" 
console.log('person2 is ' + person2.firstName); // logs "person2 is Bob" 

因爲,一段時間new聲明的情況下失敗,我沒有得到error太..

特別是在javascriptoops概念需要不同的方法。

有些時候,我很困惑,甚至沒有呼籲new關鍵詞它一切工作正常..使用new關鍵字和不使用它之間有什麼不同?

例如:

var setColor = function (color) { 
    return color; 
} 

var x = setColor('red'); 
var y = setColor('blue'); 

console.log(y); 
console.log(x); 
+0

你有什麼樣的代碼是造成'new'操作失敗?可以/應該改變這個問題來詢問你的具體情況,以及爲什麼'new'失敗,而不是尋找實例化對象實例的替代方法? – 2015-03-02 05:13:48

+0

@JoelCox - 我更新了我的問題。我同意我們需要'new'關鍵字,但是甚至省略我沒有看到任何區別。 – 3gwebtrain 2015-03-02 05:16:38

+0

請注意,使用* new *調用時,函數**必須返回一個對象。在上面,你傳遞一個原始字符串,所以構造函數返回由* this *引用的新對象,而不是字符串。 – RobG 2015-03-02 05:35:29

回答

1

new [Function]關鍵字做很多事情,但它的主要事情是:

  • 創建新的對象
  • 用途[功能]的原型作爲父原型的新對象
  • 執行[功能]的內容,使用this作爲對新的對象

參考如果調用這樣的功能,而不newthis參考將被確定爲通常爲函數確定的方式,並且通常這將是全局對象。

有一兩件事可以做,以更方便地捕捉這些錯誤是使用嚴格模式:

"use strict"; 

var Person = function (firstName) { 
    this.firstName = firstName; 
    console.log('Person instantiated'); 
}; 

var person1 = Person('Alice'); 

如果上面的代碼被執行,thisnull而不是全局對象,你會得到一個錯誤,而不是將屬性分配給全局對象(並且具有難以捕捉的錯誤)。

避免這些各種錯誤與new一種方法完全是簡單的讓函數返回一個新的對象,而不是作爲一個構造函數:

var person = function (firstName) { 
    console.log('person instantiated'); 
    return { 
     firstName: firstName 
    }; 
}; 

var person1 = person('Alice'); 
var person2 = person('Bob'); 

如果你做到這一點,不要緊,無論你使用new或不使用,因爲該功能不使用this

編輯下面有一個關於原型的問題。如果你不熟悉的原型,這是一個功能,允許您指定將一個對象的所有實例之間共享的屬性和方法:

"use strict"; 

var Person = function (firstName) { 
    this.firstName = firstName; 
    console.log('Person instantiated'); 
}; 

Person.prototype.getMyName = function() { 
    return this.firstName; 
}; 

var person1 = new Person('Alice'); 
console.log(person1.getMyName()); 

如果你這樣做,然後用new Person()創建的所有實例將共享方法getMyName

new稀少選項我詳細後來也提供這種自動延期的原型,但也可以選擇:

選擇1 - 不使用的原型:

var person = function (firstName) { 
    console.log('person instantiated'); 
    return { 
     firstName: firstName, 
     getMyName: function() { 
      return this.firstName; 
     } 
    }; 
}; 

選項2 - 使用Object.create()擴展原型:

var person = function (firstName) { 
    console.log('person instantiated'); 
    var person = Object.create(person.prototype); 
    person.firstName = firstName; 

    return person; 
}; 

選項3 - 使用一個.extend()方法原型的內容複製到一個新的對象:

var person = function (firstName) { 
    console.log('person instantiated'); 

    return _.extend({ 
     firstName: firstName 
    }, person.prototype); 
}; 

.extend()沒有內置到JavaScript,但一些庫,如jQuery和lodash提供它本質上等同的實現。

+0

這種方法怎麼樣? http://jsfiddle.net/2bLy2ctL/ – 3gwebtrain 2015-03-02 05:30:03

+0

但是,返回的對象不會從構造函數的原型繼承,它將只繼承* Object.prototype *。 – RobG 2015-03-02 05:31:05

+0

是的,到底我在這裏混淆了......你能告訴我什麼是錯誤的,我的方法是什麼,它是什麼意思'繼承構造函數的原型'通過簡單的例子..? – 3gwebtrain 2015-03-02 05:32:19

2

使用new關鍵字,當你調用一個函數設置函數內部的上下文(this)是一個新實例化的對象,而不是window或其他一些方面,這就是爲什麼你可以在該函數內部指定this.firstName,然後將其稱爲person1.firstName。

如果不使用new關鍵字,則值爲this WONT是空白對象,因此您將分配給window。在這種情況下,您想使用new,因爲您將該函數用作構造函數。如果您不打算將該函數用作構造函數,則不需要使用new來調用它。

+0

是否有任何其他apporach使這種情況..我知道的知識... – 3gwebtrain 2015-03-02 05:23:59

+0

當然,你可以用對象文字手動創建它們:var person1 = {firstName:「Alice」}'或者你可以創建一個函數,返回一個你創建的新對象,其類型如下:'var person = function(name){return {firstName:name}}'並用person(「Alice」)調用它,但在這種情況下,它更習慣於構造函數,並像原來的問題一樣用'new'來調用它。 – wrshawn 2015-03-02 05:26:51

+0

您可以評價這種方法:http://jsfiddle.net/2bLy2ctL/ – 3gwebtrain 2015-03-02 05:28:22

1

我認爲您需要更好地瞭解對象和原型如何在Javascript中工作。

考慮你有一個用例,你需要一個代表user的對象,並存儲他們的first_name

不使用任何功能,你可以簡單地與你想要的屬性,可創建一個對象:

var person = { 
    first_name: 'joel' 
}; 

這是一個標準的JavaScript對象 - 沒有什麼特別可言,也沒有新的關鍵字的使用來構建它。另一種語法來完成同樣的事情將是:

var person = new Object(); 
person.first_name = 'joel'; 

再次 - 這僅僅是一個標準的對象 - 沒有什麼特別的。

創建new函數實例的主要原因是使用javascript的原型系統。這與其他語言的類相似。假設你想要一個人的所有實例都有一個名爲getName()的方法。你可以確保你對每個人都有這種方法...

var person = { 
    first_name: 'joel', 
    getName: function() { 
     return this.first_name; 
    } 
}; 

or ...

var person = new Object(); 
person.first_name = 'joel'; 
person.getName = function() { 
    return this.first_name; 
}; 

然而,對於這樣的事情,在這裏你總是會希望爲每個用戶定義的這個方法更好的方法,是創建一個person對象的新實例,並定義上的getName方法人身函數的原型屬性:

function Person() {} 
Person.prototype.getName = function() { 
    return this.first_name; 
} 

var user = new Person(); 
user.first_name = 'joel'; 
console.log(user.getName()); 

......或根據你的榜樣,你可以用一個參數來Person構造函數來設置的第一個名字屬性:

function Person(first_name) { 
    this.first_name = first_name; 
} 
Person.prototype.getName = function() { 
    return this.first_name; 
}; 
var user = new Person('joel'); 
console.log(user.getName()); 

請注意,使用此方法時,您始終會在創建Person實例時使用new關鍵字。當你考慮到followng這樣做的原因變得清晰:

function Person() {this.first_name = 'joel'; return 'test';} 
console.log(window.first_name); // Undefined, as expected 
console.log(Person()); // Shows "test"; 
console.log(window.first_name); // shows "joel". 
console.log(new Person()); // Shows "{first_name: 'joel'}" 

注意,以上4行,你可以看到,通過省略一個函數調用,希望你可以使用它的new關鍵字,你意外地修改了window對象上的屬性,而不是將其設置爲新的常規對象。

有效地 - 您可以考慮使用new關鍵字來導致人員功能的返回值被廢除,取而代之的是您將返回人員對象的新實例。

另外請注意,你可以從你的函數中省略new關鍵字如果this等於減少window對象的意外修改的風險,通過檢查window並返回你的函數的一個新實例,而不是:

function Person() { 
    if (this === window) return new Person(); 
    this.first_name = 'joel'; 
} 

通過上述,您可以使用以下兩種方法的實例化對象person,都將有同樣的效果:

var user1 = new Person(); 
var user2 = Person(); 

有關函數和原型對象如何JavaScript的工作,我建議您閱讀使用閉包,而不是對象http://www.w3schools.com/js/js_object_prototypes.asp

1

另一種可能的結構在所有

一些更多的信息,這種結構也可以被嵌套在創建私有靜態變量

它有沒有用這個單詞的

var thing = function(private_var){ 

    function get(){ 
    console.log(private_var) 
    } 

    function set(z){ 
     private_var = z 
    } 

    return { 
    get:get, 
    set:set 
    } 


} 

var x = thing(0) 
var y = thing(1) 

請注意:
這使得CE rtain類型的程序員的怪胎和恐慌

& &重要x.say!== y.say