new原理及模擬實現

簡介new

new 運算符是創建一個用戶定義的對象類型的實例或具有構造函數的內置對象的實例,其創建過程如下:

  • 創建一個空的簡單JavaScript對象(即{})
  • 鏈接該對象(即設置該對象的構造函數)到另一個對象
  • 將第一步新創建的對象作爲this的上下文
  • 如果該函數沒有返回對象,則返回this

舉個栗子:

function Person(name,age){
    this.name = name;
    this.age = age;
    this.habit = "swim";
}

Person.prototype.sex = 'female';

Person.prototype.sayHello = function(){
    console.log('Hello!My name is ' + this.name);
}

var person = new Person('Youxuan','20');

console.log(person.name);   //Youxuan
console.log(person.habit);  //swim
console.log(person.sex);    //female
person.sayHello();  //Hello!My name is Youxuan

從上述內容中,可以看出實例訪問到Person構造函數裏的屬性,
也可以訪問到Person.prototype裏的屬性;
因此,我們可以嘗試模擬一下new的實現方法,先來回顧一下new是如何使用的

function Person(){
    ...
}
var person = new Person(...);
var person = newObject(...);

初步模擬

因爲new的結果是一個對象,所以在實現new的過程中,也要生成一個新的對象。我們先將這個對象命名爲obj,因爲obj也具有Person構造函數的屬性,所有要通過調用父類,繼承父類實例的方式,來給obj添加新屬性。

回顧上一篇文章,我們講解了原型和原型鏈,把obj的proto指向構造函數Person的原型對象prototype,此時便建立了obj對象的原型鏈:

obj->Person.prototype->Object.prototype->null,實例以此關係來訪問原型上的屬性

function newObject(){
    var obj = new Object();
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    Constructor.apply(obj,arguments);
    return obj;
}

在以上內容中,通過new Object()創建了一個對象obj。

取出第一個參數,就是我們要傳入的構造函數。因爲shift會修改原數組,所以arguments會被去除第一個參數。

將obj的原型指向構造函數,這樣obj就可以訪問到構造函數原型中的屬性。

利用apply,改變構造函數this指向到新建對象,這樣obj就能訪問到構造函數中的屬性,然後返回obj。

現在,我們寫一段代碼來驗證一下效果:

function Person(name,age){
    this.sex = 'female';
    this.age = age;
    return {
        name: name,
        habit: 'swim'
    }
}
var person = new Person('Youxuan','20');
console.log(person.name);   //Youxuan
console.log(person.habit);  //swim
console.log(person.sex);    //undefined
console.log(person.age);    //undefined

以上代碼中,構造函數返回了一個對象,在實例person中只能訪問返回的對象中的屬性。

而且另需注意,這裏返回的是一個對象,假若需要返回一個基本類型的數據時該怎麼辦呢?

function Person(name,age){
    this.sex = 'female';
    this.age = age;
    return 'Beauty on my face'
}
var person = new Person('Youxuan','20');
console.log(person.name);       //undefined
console.log(person.habit);      //undefined
console.log(person.sex);        //female
console.log(person.age);        //20

這時結果跟上次完全相反,儘管這次有返回值,但是相當於沒有對返回值進行處理。

效果實現

所以仍需判斷返回值是不是一個對象,如果是一個對象,就返回這個對象;如果不是一個對象,那就將它直接返回:

function newObject(){
    var obj = new Object();
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    var demo = Constructor.apply(obj,arguments);
    return typeof demo === 'object' ? demo : obj;
}

至此就模擬實現了new操作符的效果,主要原理就是原型鏈apply繼承。

對此你有什麼感受呢,歡迎添加微信進行交流。


圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章