JS面向對象編程(二):構造函數

1、什麼是構造函數?

  構造函數 ,是一種特殊的方法。主要用來爲對象成員變量賦初始值,總與new運算符一塊兒使用在建立對象的語句中,對於JavaScript的內置對象Number()、String()、Boolean()、Object()、Array()、Function()、Date()、RegExp()、Error()等都是構造函數;
bash

構造函數的特色:

  1. 構造函數的首字母大寫,用來區分於普通函數
  2. 內部使用的this對象,來指向即將要生成的實例對象
  3. 使用New來生成實例對象

舉個栗子:

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 操做符來調用,那它就能夠做爲構造函數函數

2、構造函數與對象

  上一節咱們說到在JavaScript中,幾乎全部的事物都是對象:對象只是帶有屬性和方法的特殊數據類型
  可是基本類型值不是對象,於是從邏輯上講它們不該該有方法,實際上咱們建立 String 類型時後臺自動作了一些處理:this

  1. 建立 String 類型的一個實例;
  2. 在實例上調用指定的方法;
  3. 銷燬這個實例。
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 操做符建立的引用類型的實例, 在執行流離開當前做用域以前都一直保存在內存中。而自動建立的基本包裝類型的對象,則只存在於一 行代碼的執行瞬間,而後當即被銷燬;設計

3、建立實例對象

要建立 Person 的新實例,必須使用 new 操做符,調用構造函數建立對象通過了如下幾個過程:指針

  1. 建立一個新對象;
  2. 將構造函數的做用域賦給新對象(所以 this 就指向了這個新對象);
  3. 執行構造函數中的代碼(爲這個新對象添加屬性);
  4. 返回新對象;

  在前面例子中,person1 和 person2分別保存着Person的一個不一樣的實例。這兩個對象都有一個constructor(構造函數) 屬性,該屬性指向 Person:code

console.log(person1.constructor == Person); //true 
console.log(person2.constructor == Person); //true 
複製代碼

4、判斷對象類型

  在JS中判斷一個變量的類型常常會用 typeof 運算符,可是在使用 typeof 運算符來判斷引用類型時,不管引用的是什麼類型的對象,它都返回"object"。因此在判斷對象的類型時咱們可使用 instanceof 運算符:對象

console.log(person1 instanceof Object); //true 
複製代碼

5、 構造函數缺點

  使用構造函數時每一個方法都要在每一個實例上從新建立一遍: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 高級程序設計》中文譯本 第三版

相關文章
相關標籤/搜索