js new一個對象的過程,實現一個簡單的new方法


對於大部分前端開發者而言,new一個構造函數或類得到對應實例,是非常普遍的操作了。下面的例子中分別通過構造函數與class類實現了一個簡單的創建實例的過程。

// ES5構造函數
let Parent = function (name, age) {
    this.name = name;
    this.age = age;
};
Parent.prototype.sayName = function () {
    console.log(this.name);
};
const child = new Parent('test', 26);
child.sayName() //'test'


//ES6 class類
class Parent {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        console.log(this.name);
    }
};
const child = new Parent('test', 26);
child.sayName() //test

一、new操作中發生了什么?

比較直觀的感覺,當我們new一個構造函數,得到的實例繼承了構造器的構造屬性(this.name這些)以及原型上的屬性

在《JavaScript模式》這本書中,new的過程說的比較直白,當以new操作符調用構造函數時,函數內部將會發生以下情況:

• 創建一個空對象並且this變量引用了該對象,同時還繼承了該函數的原型。
• 屬性和方法被添加至this引用的對象中。
• 新創建的對象由this所引用,並且最后隱式地返回 this(如果沒有顯式的返回其它的對象)

我們改寫上面的例子,大概就是這樣:

// ES5構造函數
let Parent = function (name, age) {
    //1.創建一個新對象,賦予this,這一步是隱性的,
    // let this = {};
    //2.給this指向的對象賦予構造屬性
    this.name = name;
    this.age = age;
    //3.如果沒有手動返回對象,則默認返回this指向的這個對象,也是隱性的
    // return this;
};
const child = new Parent();

將this賦予一個新的變量(例如that),最后返回這個變量:

// ES5構造函數
let Parent = function (name, age) {
    let that = this;
    that.name = name;
    that.age = age;
    return that;
};
const child = new Parent('test', '26');

this的創建與返回是隱性的,手動返回that的做法;這也驗證了隱性的這兩步確實是存在的。

二、實現一個簡單的new方法(winter大神)

• 以構造器的prototype屬性為原型,創建新對象;
• 將this(也就是上一句中的新對象)和調用參數傳給構造器,執行;
• 如果構造器沒有手動返回對象,則返回第一步創建的新對象,如果有,則舍棄掉第一步創建的新對象,返回手動return的對象。

new過程中會新建對象,此對象會繼承構造器的原型與原型上的屬性,最后它會被作為實例返回這樣一個過程。

// 構造器函數
let Parent = function (name, age) {
    this.name = name;
    this.age = age;
};
Parent.prototype.sayName = function () {
    console.log(this.name);
};
//自己定義的new方法
let newMethod = function (Parent, ...rest) {
    // 1.以構造器的prototype屬性為原型,創建新對象;
    let child = Object.create(Parent.prototype);
    // 2.將this和調用參數傳給構造器執行
    let result = Parent.apply(child, rest);
    // 3.如果構造器沒有手動返回對象,則返回第一步的對象
    return typeof result  === 'object' ? result : child;
};
//創建實例,將構造函數Parent與形參作為參數傳入
const child = newMethod(Parent, 'echo', 26);
child.sayName() //'echo';

//最后檢驗,與使用new的效果相同
child instanceof Parent//true
child.hasOwnProperty('name')//true
child.hasOwnProperty('age')//true
child.hasOwnProperty('sayName')//false

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM