Stories

Detail Return Return

模擬實現js中的new操作符 - Stories Detail

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

這是MDN上對new操作符的定義,從這句話中可以看出new返回的其實就是一個實例,那麼問題來了實例又是個啥東西?

先看個例子:

function Cat(name, gender) {
    this.name = name;
    this.gender = gender;
}

Cat.prototype.say = () => {
    console.log('miao, miao, miao');
}

const cat = new Cat('Tom', 'male');
console.log(cat.name); /* Tom */
console.log(cat.gender); /* male */
cat.say(); /* miao, miao, miao */
console.log(typeof cat); /* object */

從例子中可以看到,new操作符返回的其實是一個對象,這個對象可以訪問到構造函數中屬性和方法。那麼就很明顯了,在js中,所有對象都包含一個__proto__屬性指向構造函數的原型,在對象上查找屬性時會順着__proto__一直向上查找。

相關:簡單説説原型和原型鏈

new的實現就簡單了啊。

/* 因為new是關鍵詞,所以用方法替代 */
function newObj() {
    const obj = {};
    const Constructor = Array.prototype.shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    Constructor.apply(obj, arguments);
    return obj;
}

對apply不熟悉的童鞋可能會對Constructor.apply(obj, arguments);這句代碼有疑問。

function Cat(name, gender) {
    this.name = name;
    this.gender = gender;
}

const obj = {};
Cat.apply(obj, 'Tom', 'Mole'); // Constructor.apply(obj, arguments);
// 就相當於
obj.name = 'Tom';
obj.gender = 'Mole';

使用newObj來替換new會發現貌似沒有問題,可以正常運行。可是當我們稍稍修改一下上述代碼就會發現運行結果會不一樣。

function Cat(name, gender) {
    this.name = name;
    this.gender = gender;
    return { name: 'Jerry', skin: 'block' };
}

Cat.prototype.say = () => {
    console.log('miao, miao, miao');
}

const cat = new Cat('Tom', 'male');
console.log(cat.name); /* Jerry */
console.log(cat.gender); /* undefined */
console.log(typeof cat); /* object */
cat.say(); /* TypeError: cat.say is not a function */

可以發現,當構造函數裏面有返回值時,明顯new操作符應該返回的對象是構造函數裏面的返回值(僅當返回值是對象時有效)。
修改之前的代碼。

function newObj() {
    const obj = {};
    const Constructor = Array.prototype.shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    const ret = Constructor.apply(obj, arguments);
    return typeof ret === 'object' ? ret : obj;
}

以上就是關於new的模擬實現。最後再貼上MDN上的描述:

  1. 創建一個空的簡單JavaScript對象(即{});
  2. 鏈接該對象(即設置該對象的構造函數)到另一個對象 ;
  3. 將步驟1新創建的對象作為this的上下文 ;
  4. 如果該函數沒有返回對象,則返回this。
user avatar toopoo Avatar front_yue Avatar zourongle Avatar hard_heart_603dd717240e2 Avatar xiaolei_599661330c0cb Avatar hyfhao Avatar b_a_r_a_n Avatar yanyue404 Avatar sy_records Avatar tizuqiudehongcha Avatar hu_qi Avatar wubomu Avatar
Favorites 48 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.