構造函數 ,是一種特殊的方法。主要用來爲對象成員變量賦初始值,總與new運算符一塊兒使用在建立對象的語句中,對於JavaScript的內置對象Number()、String()、Boolean()、Object()、Array()、Function()、Date()、RegExp()、Error()等都是構造函數;
bash
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayHello = function(){
console.log(this.name+":Hello!");
};
}
var person1 = new Person("lilei", 26, "Teacher"); //實例對象 person1
var person2 = new Person("xiaom", 27, "Doctor"); //實例對象 person2
複製代碼
構造函數與其餘函數的惟一區別,就在於調用它們的方式不一樣。構造函數畢竟也是函數,不存在定義構造函數的特殊語法。任何函數,只要經過 new 操做符來調用,那它就能夠做爲構造函數函數
上一節咱們說到在JavaScript中,幾乎全部的事物都是對象:對象只是帶有屬性和方法的特殊數據類型
可是基本類型值不是對象,於是從邏輯上講它們不該該有方法,實際上咱們建立 String 類型時後臺自動作了一些處理:this
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;
複製代碼
基本類型值不是對象,只有引用類型是對象,可是 咱們可讓String成爲引用類型:spa
var s1 = new String("some text");
複製代碼
當咱們手動new一個字符串s1的時候,s1既是String又是引用類型,因此他是一個對象;prototype
引用類型與基本包裝類型的主要區別就是對象的生存期。使用 new 操做符建立的引用類型的實例, 在執行流離開當前做用域以前都一直保存在內存中。而自動建立的基本包裝類型的對象,則只存在於一 行代碼的執行瞬間,而後當即被銷燬;設計
要建立 Person 的新實例,必須使用 new 操做符,調用構造函數建立對象通過了如下幾個過程:指針
在前面例子中,person1 和 person2分別保存着Person的一個不一樣的實例。這兩個對象都有一個constructor(構造函數) 屬性,該屬性指向 Person:code
console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true
複製代碼
在JS中判斷一個變量的類型常常會用 typeof 運算符,可是在使用 typeof 運算符來判斷引用類型時,不管引用的是什麼類型的對象,它都返回"object"。因此在判斷對象的類型時咱們可使用 instanceof 運算符:對象
console.log(person1 instanceof Object); //true
複製代碼
使用構造函數時每一個方法都要在每一個實例上從新建立一遍:ip
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayHello = function(){
console.log(this.name+":Hello!");
};
//this.sayHello = new Function('console.log(this.name+":Hello!")')
}
複製代碼
new Function與聲明函數在邏輯上是同樣的,因此每次實例化Person對象時,sayHello 方法也是一個新實例,因此:
console.log(person1.sayName == person2.sayName); //false
複製代碼
注意:person1.sayName 與person1.sayName()不同,person1.sayName()是指函數返回值,person1.sayName是指函數自己;
建立兩個完成一樣任務的 Function 實例的確沒有必要,所以,咱們能夠經過把函數定義轉移到構造函數外部來解決這個問題。例如:
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayHello = sayHello;
}
function sayHello(){
console.log(this.name+":Hello!");
}
複製代碼
這樣將 sayName 屬性設置成指向全局函數 sayName() 的指針。sayName()只被實例化一次; 可是若是對象須要定義不少方法,那麼就要定義不少個全局函數。並且在全局做用域中定義的函數實際上只被某個對象調用,這樣不符合全局函數的理念。咱們這個自定義的引用類型也絲毫沒有封裝性可言。好在這些問題能夠經過使用原型模式來解決。因此下一節《 prototype(原型)》
《JavaScript 高級程序設計》中文譯本 第三版