JavaScript溫故而知新——new操做符的實現

首先咱們要知道new 操做符具體作了些什麼?數組

  1. 建立一個空對象
  2. 而後讓這個空對象的__proto__指向函數的原型prototype
  3. 執行構造函數中的代碼,構造函數中的this指向該對象
  4. 若是構造函數有返回值,則以該對象做爲返回值。若沒有returnreturn了基本類型,則將新對象做爲返回值

若是對於原型還不是很瞭解的話建議先看看:JavaScript溫故而知新——原型和原型鏈bash

先來實現前三點的效果:閉包

function new2() {
    // 新建一個對象
    var obj = new Object(),
    
    // 取得第一個參數,即傳入的構造函數。
    // 這裏 shift 會修改原數組,所以 arguments 會被去掉第一個參數
    Constructor = [].shift.call(arguments);
    
    // 將 obj 的原型指向構造函數,這樣 obj 就能夠訪問到構造函數原型中的屬性了
    obj.__proto__ = Constructor.prototype;
    
    // 使用 apply ,改變構造函數 this 的指向到新建的對象,這樣 obj 就能夠的訪問到構造函數中的屬性了
    Constructor.apply(obj, arguments);
    return obj;
};
複製代碼

咱們能夠作個測試app

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype.sayName = function() {
    console.log('I am' + this.name);
}
var person = new2(Person, 'xiao', '18')

console.log(person.name)    // xiao
console.log(person.age)     // 18
person.sayName();           // I am xiao
複製代碼

實現返回值的效果函數

假如構造函數是有返回值,而且返回值是一個對象:post

function Person(name, age) {
    this.skill = 'eat';
    this.age = age;
    return {
        name: name,
        habit: 'sleep'
    }
}
var person = new Person('xiao', '18')

console.log(person.name)    // xiao
console.log(person.habit)     // sleep
console.log(person.skill)    // undefined
console.log(person.age)     //  undefined
複製代碼

能夠看到實例person中只能訪問返回的對象中的屬性,說明此時new的返回值爲構造函數Person return 出來的對象。測試

假如構造函數的返回值是一個基本類型的值:ui

function Person(name, age) {
    this.skill = 'eat';
    this.age = age;
    return 'hello world'
}
var person = new Person('xiao', '18')

console.log(person.name)    // undefined
console.log(person.habit)     // undefined
console.log(person.skill)    // eat
console.log(person.age)     //  18
複製代碼

能夠看到實例person能夠正常訪問構造函數中的屬性,說明此時new的返回值爲新建立的原型指向構造函數的對象。this

按照上面的結論來完整實現咱們的new2spa

function objectFactory() {

    var obj = new Object(),

    Constructor = [].shift.call(arguments);

    obj.__proto__ = Constructor.prototype;

    var ret = Constructor.apply(obj, arguments);

    // 判斷構造函數返回值是否爲對象,是的話返回這個對象,不是則正常返回
    return typeof ret === 'object' ? ret : obj;

};
複製代碼

結尾

系列文章:

相關文章
相關標籤/搜索