您是否曾困惑於 Javascript 中的new關鍵字呢?是否曾想理解關於 function 和 constructor 的區別是什麼呢?javascript
大多數 Javascript 的新開發者不太想要使用new關鍵字,由於這會讓代碼寫的像是 Java 而且在使用上會形成一點混亂;在這篇文章我會盡可能嘗試着去理清這些東西,並解釋它是如何運做的。java
constructor
翻爲構造器但爲了讓您以後更好地理解,會直接使用 constructor
;在 Javascript 中任何一個函數(function
)均可以被看成 constructor
;Javascript 並無明確的區分二者,也就是說 function
能夠被看成 constructor
或者看成通常函數調用。git
而 constructor
的用法就是 function
搭配new
關鍵字:github
function Person ( ) {
this . firstName = 'Jay' ;
this . lastName = 'Chou' ;
}
var person = new Person ( ) ;
console . log ( person ) ;
複製代碼
接着咱們把person
呼叫出來看,會獲得以下的結果,經過new
它會幫咱們創建一個對象,而後裏面有Person
這個function
裏面的內容,而且變成了屬性名稱和屬性值:chrome
當使用new
命令時,它後面的函數依次執行下面的4個步驟:數組
prototype
屬性。this
關鍵字。new
表達式中的函數調用會自動返回這個新對象。也就是說,當咱們使用new
這個關鍵字時,實際上會先有一個空的對象被創建。app
接着People
這個構造函數會被執行,這個空對象的原型,指向了People.prototype
。函數
咱們知道當函數執行的時候,在execution context
中會有this
被創建,而當咱們使用new
的時候,函數裏面的this
會被指定成剛剛所創建的那個空對象。ui
因此當執行People
這個function
,執行到this.firstName
和this.lastName
時,由於this
如今指稱的是那個空對象,因此其實是在幫這個空對象賦予屬性名稱和屬性值。this
在這樣的過程當中,只要這個構造函數People
沒有指定return
爲其餘對象,它就會直接返回給咱們這個新創建的對象。
接着讓咱們經過一段代碼來更清楚的瞭解這個執行的過程:
function Person ( ) {
this . firstName = 'Jay' ;
this . lastName = 'Chou' ;
console . log ( '這個函數有被執行' ) ;
}
var person = new Person ( ) ;
console . log ( person ) ;
複製代碼
這時候在chrome 中呼叫出來的結果以下,說明了當咱們使用new
在構造對象的時候People
這個function
確實有被執行:
如今我把咱們上面的代碼改爲這樣:
function Person ( ) {
console . log ( this ) ;
}
var person = new Person ( ) ;
// console.log(person);
複製代碼
這時候代碼返回的結果以下,表示的確在執行這段代碼的過程當中幫咱們創建了一個新的空對象:
如今,讓咱們把本來的代碼稍微作以下修改:
function Person ( ) {
this . firstName = 'Jay' ;
this . lastName = 'Chou' ;
return { "RETURN" : "本來this的內容就不會被返回" } ;
}
var person = new Person ( ) ;
console . log ( person ) ;
複製代碼
構造函數的內部若return
其餘對象,new
命令會返回return
語句指定的對象,將原新對象內容覆蓋掉;不然,就會無論return
語句,返回this
對象。返回的結果以下:
function create() {
// 建立一個空的對象
var obj = new Object(),
// 得到構造函數,arguments中去除第一個參數
Con = [].shift.call(arguments);
// 連接到原型,obj 能夠訪問到構造函數原型中的屬性
obj.__proto__ = Con.prototype;
// 綁定 this 實現繼承,obj 能夠訪問到構造函數中的屬性
var ret = Con.apply(obj, arguments);
// 優先返回構造函數返回的對象
return ret instanceof Object ? ret : obj;
};
複製代碼
使用這個手寫的new
function Person() {...}
// 使用內置函數new
var person = new Person(...)
// 使用手寫的new,即create
var person = create(Person, ...)
複製代碼
代碼原理解析:
new Object()
的方式新建了一個對象obj
shift
會修改原數組,因此 arguments
會被去除第一個參數obj
的原型指向構造函數,這樣obj
就能夠訪問到構造函數原型中的屬性apply
,改變構造函數 this
的指向到新建的對象,這樣 obj
就能夠訪問到構造函數中的屬性obj
由上面的方法,咱們能夠經過function
的方式來創建一個新的對象,若是咱們想要創建出同屬性名稱但不一樣屬性值的對象內容,咱們能夠把對象的屬性值變成參數,如此就能經過此function constructor
創建出許多不一樣的對象:
function Person ( firstName , lastName ) {
this . firstName = firstName ;
this . lastName = lastName ;
}
var person1 = new Person ( 'Jay' , 'chou' ) ;
console . log ( person1 ) ;
var person2 = new Person ( 'Jane' , 'chou' ) ;
console . log ( person2 ) ;
複製代碼
如此,咱們就能夠經過同一個構造函數創建出不少不一樣的對象:
此外,咱們會把根據構造器(constructor
)所創建出來的對象稱做是實例(instance
),這在以前的文章裏也有提過。
這裏有一個地方咱們須要很是留意,若是你在撰寫代碼的過程中,忘記加上new
這個關鍵字的話,好比:
function Person ( ) {
this . firstName = 'Jay' ;
this . lastName = 'Chou' ;
}
var person = Person ( ) ;
console . log ( person ) ;
複製代碼
如此,由於JavaScript不知道你是要執行這個函數,仍是要根據這個function
去創建object
,因次最後會返回undefined
的結果。
那又是如何經過function constructors
來設定咱們的原型(prototype
)呢?讓咱們在下一篇文章來談吧!
若是以爲文章對你有些許幫助,歡迎在個人GitHub博客點贊和關注,感激涕零!