JS系列-趣談new

最近天氣好冷,上下班騎着小電驢,風吹得整我的都是冰冰的,小夥伴要注意保暖,千萬別冷到了。markdown

new簡介

咱們先來看看MDN上給出的簡介app

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

new 關鍵字你們都不陌生,用來給構造函數建立實例的,可是 new 它到底幹了些什麼,可能就不是很清楚了,下面我來給你們解開 new 的神祕面紗。oop

咱們先來複習下 new 的使用,來看看 new 的功能,先知道 new 作了什麼事情才能更好的去實現它。測試

function Pig(name, age{
    this.name = name;
    this.age = age;
    this.habit = '吃棒棒糖';
}

Pig.prototype.sayName = function({
    console.log('我叫' + this.name);
}

Pig.prototype.skill = '降龍十巴掌!(๑•̀ㅂ•́) ✧';

let GGBond = new Pig("豬豬俠"13);

console.log(GGBond); // Pig { name: '豬豬俠', age: 13, habit: '吃棒棒糖', __proto__: Object }
console.log(GGBond.name); // 豬豬俠
console.log(GGBond.skill); // 降龍十巴掌!(๑•̀ㅂ•́) ✧
GGBond.sayName(); // 我叫豬豬俠
複製代碼

經過上面的栗子咱們能夠看到 new 出來的實例對象:ui

  1. 能訪問到構造函數 Pig 中的私有屬性
  2. 能訪問到構造函數 Pig.prototype 上的屬性

new的實現

經過上面的例子咱們已經明白了 new 的功能了,可是具體 new 是怎麼作到的呢?讓咱們來看看MDNthis

  1. 建立一個空的簡單JavaScript對象(即{});
  2. 連接該對象(設置該對象的constructor)到另外一個對象 ;
  3. 將步驟1新建立的對象做爲this的上下文 ;
  4. 若是該函數沒有返回對象,則返回this。

咱們跟着這個功能來一步步實現 new 吧!spa

建立空對象

建立一個空的簡單JavaScript對象(即{});prototype

  • 由於 new 是關鍵字,沒辦法覆蓋,全部咱們使用函數來模擬 new 的效果,將構造函數以第一個參數進行傳入
function myNew(Ctor, ...args{
    let obj = {}; 
}
複製代碼

連接對象

連接該對象(設置該對象的constructor)到另外一個對象 ;code

  • 由於咱們的實例須要可以訪問到構造函數的原型,咱們將新對象的 proto 指向構造函數,js 會經過這個屬性向上查找原型鏈,立個flag,下週我會繼續出一篇關於原型鏈的文章,有興趣的小夥伴能夠點個關注。
function myNew(Ctor, ...args{
    let obj = {}; 
    obj.__proto__ = Ctor.prototype;
}
複製代碼

修改上下文

將步驟1新建立的對象做爲this的上下文 ;

  • 修改上下文的方法有不少, bind 、 call 、apply 均可以修改咱們的上下文,這裏我使用 apply 進行修改,注意這裏還隱式包含了指行一次構造函數。
  • 綁定 this 指向建立的實例對象
function myNew(Ctor, ...args{
    let obj = {}; 
    obj.__proto__ = Ctor.prototype;
    const result = Ctor.apply(obj, args);
}
複製代碼

返回結果

若是該函數沒有返回對象,則返回this。

function myNew(Ctor, ...args{
    let obj = {}; // 建立實例對象
    obj.__proto__ = Ctor.prototype; // 原型鏈繼承
    const res = Ctor.apply(obj, args); // 修改 this 指向實例
    if (/^(object|function)$/.test(typeof res)) return res; // 構造函數返回的是對象就直接該返回該結果
    return obj; // 不然返回實例
}
複製代碼

測試功能

代碼寫完了,咱們來執行上面的例子來看下是否和原生 new 表現一致

function Pig(name, age{
    this.name = name;
    this.age = age;
    this.habit = '吃棒棒糖';
}
Pig.prototype.sayName = function({
    console.log('我叫' + this.name);
}
Pig.prototype.skill = '降龍十巴掌!(๑•̀ㅂ•́) ✧';

function myNew(Ctor, ...args{
    let obj = {}; // 建立一個實例對象
    obj.__proto__ = Ctor.prototype;
    const res = Ctor.apply(obj, args);
    if (/^(object|function)$/.test(typeof res)) return res;
    return obj;
}

let myGGBond = myNew(Pig, "豬豬俠"13);

console.log(myGGBond); // Pig { name: '豬豬俠', age: 13, habit: '吃棒棒糖', __proto__: Object }
console.log(myGGBond.name); // 豬豬俠
console.log(myGGBond.skill); // 降龍十巴掌!(๑•̀ㅂ•́) ✧
myGGBond.sayName(); // 我叫豬豬俠

// 測試返回函數

function Dog(name{
    this.name = name;
    this.habit = '吃骨頭';
    return function({
        console.log('隨便輸出點什麼吧');
    }
}
let myDog = myNew(Dog, '金毛');
console.log(myDog); // ƒ () {...}

// 測試返回對象
function Cat(name{
    this.name = name;
    this.habit = '吃魚';
    return {
        name
    }
}
let myCat = myNew(Cat, '黑貓警長');
console.log(myCat); // { name: '黑貓警長' }
複製代碼

能夠看到和原生的 new 結果是同樣的。

很是感謝各位能閱讀到這裏,以爲有幫助的話不妨點個贊,你的支持是對我對最大的鼓勵。

相關文章
相關標籤/搜索