深刻理解JavaScript之 new 原理及模擬實現

1.定義

new 運算符建立一個用戶定義的對象類型的實例或具備構造函數的內置對象的實例javascript

先看看 new 實現了哪些功能, 先來看一段代碼:java

function Person(age) {
    this.age = age;
}
Person.prototype.getAge = function() {
    console.log("年齡爲:" + this.age );
}

var person = new Person(18);
person.age; // 訪問構造函數裏的屬性
// 18

person.getAge(); // 訪問原型裏的屬性
// 年齡爲:18
複製代碼

從上面代碼能夠知道,實例 person 能夠:數組

  1. 訪問到 Person 構造函數裏的屬性
  2. 訪問到 Person.prototype 中的屬性

這個是最基本的了,也是剛學會new一個對象就知道這是new的特色app

2.探討new還作了什麼?

探討完上面,接下來看看new還作了什麼?來看幾個例子函數

1. 沒有return語句

function Person(age) {
    this.age = age;
}

var person = new Person(18);
console.log(person); // Person {age: 18}
複製代碼

從構造函數直觀看,最後是沒有 return語句的,但咱們從返回結果也能夠看出構造函數時默認狀況會返回一個新對象測試

2. return 對象數據類型

咱們嘗試在構造函數最後返回一個對象ui

function Person(age) {
    this.age = age;
    return { name: '手動返回一個對象' }
}

var person = new Person(18);
console.log(person); // {name: "手動返回一個對象"}
複製代碼

打印出來的結果能夠看書:return 以前的代碼片斷都被覆蓋了,最後返回 return 後面的對象。this

3. return 基本數據類型

若是構造函數最後return的不是對象呢,試下基本數據類型spa

function Person(age) {
    this.age = age;
    return 1 
}

var person = new Person(18);
console.log(person); // Person {age: 18}
複製代碼

從打印出來的結果可知,和沒有return效果同樣。prototype

3.new原理

mdn上把內部操做大概分爲4步:

  1. 建立一個空的簡單JavaScript對象(即{ } );
  2. 連接該對象(即設置該對象的構造函數)到另外一個對象 ;(所以this就指向了這個新對象)
  3. 執行構造函數中的代碼(爲這個新對象添加屬性);
  4. 若是該函數沒有返回對象,則返回this。

4.模擬實現new

new 是關鍵詞,不能夠直接覆蓋。這裏使用 create 來模擬實現 new 的效果。

function myNew() {
    // 建立一個空的對象
    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;
};
複製代碼

來看看上面是怎麼一步步模擬實現的:

  1. 用new Object() 的方式新建了一個空對象 obj
  2. 取出第一個參數,便是傳入的構造函數。shift 會修改原數組,數組原來的第一個元素的值。
  3. 將 obj 的原型指向構造函數,這樣 obj 就能夠訪問到構造函數原型中的屬性
  4. 使用 apply,改變構造函數 this 的指向。將this指向obj對象 就能夠訪問到構造函數中的屬性
  5. 處理返回值。
  • 構造函數返回值有三種狀況:
  1. 沒有return,默認返回以前建立的對象
  2. 返回一個對象
  3. 返回的不是對象,默認返回以前建立的空對象

在上面咱們用instanceof方法來判斷是否爲對象

instanceof 運算符用於檢測構造函數的 prototype 屬性是否出如今某個實例對象的原型鏈上。

測試:

function Person(age) {
    this.age = age;
}
Person.prototype.getAge = function() {
    console.log("年齡爲:" + this.age );
}

var person = create(Person, 18)
person.age; // 訪問構造函數裏的屬性
// 18

person.getAge(); // 訪問原型裏的屬性
// 年齡爲:18
複製代碼

模擬實現成功!

相關文章
相關標籤/搜索