new 原理及模擬實現

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

舉個栗子函數

function Car(color) {
    this.color = color;
}
Car.prototype.start = function() {
    console.log(this.color + " car start");
}

var car = new Car("black");
car.color; // 訪問構造函數裏的屬性
// black

car.start(); // 訪問原型裏的屬性
// black car start
複製代碼

能夠看出 new 建立的實例有如下 2 個特性ui

  • 訪問到構造函數裏的屬性this

  • 訪問到原型裏的屬性spa

注意點prototype

ES6新增 symbol 類型,不能夠使用 new Symbol(),由於 symbol 是基本數據類型,每一個從Symbol()返回的 symbol 值都是惟一的。3d

Number("123"); // 123
String(123); // "123"
Boolean(123); // true
Symbol(123); // Symbol(123)

new Number("123"); // Number {123}
new String(123); // String {"123"}
new Boolean(true); // Boolean {true}
new Symbol(123); // Symbol is not a constructor
複製代碼

new操做符的工做原理code

  • 一個新對象被建立,它繼承自func.prototype。
  • 構造函數func 被執行,執行的時候,相應的參數會被傳入,同時上下文(this) 會被指定爲這個新實例。
  • 若是構造函數返回了一個新對象,那麼這個對象會取代整個new出來的結果,若是構造函數沒有返回對象, 那麼new出來的結果爲步驟1建立的對象。
廢話很少說,直接上代碼
var newObj = function(func){
    var t = {}
    t.prototype = func.prototype
    var o = t
    var k =func.call(o);
    if(typeof k === 'object'){
        return k;
    }else{
        return o;
    }
}
var parent1 = newObj(Parent) //等價於new操做
複製代碼

DEMO:cdn

/**
 * new2 new關鍵字的代碼實現演示
 * @param {function} func 被new的類 (構造函數)
 */
function new2(func) {
    // 建立了一個實例對象 o,而且這個對象__proto__指向func這個類的原型對象 
    let o = Object.create(func.prototype); 
    // (在構造函數中this指向當前實例)讓這個類做爲普通函數值行 而且裏面this爲實例對象 
    let k = func.call(o);
    // 最後再將實例對象返回 若是你在類中顯示指定返回值k,
    // 注意若是返回的是引用類型則將默認返回的實例對象o替代掉
    return typeof k === 'object' ? k : o;
}

// 實驗
functionM() { // 即將被new的類
    this.name = 'liwenli';
}

let m = new2(M); // 等價於 new M 這裏只是模擬
console.log(m instanceof M); // instanceof 檢測實例
console.log(m instanceof Object);
console.log(m.__proto__.constructor === M);
複製代碼

Object.create 兼容實現對象

let obj1 = {id: 1};
        Object._create = (o) => {
            let Fn = function() {}; // 臨時的構造函數
            Fn.prototype = o;
            return new Fn;
        }
        
        let obj2 = Object._create(obj1);
        console.log(obj2.__proto__ === obj1); // true
        console.log(obj2.id); // 1

        // 原生的Object.create
        let obj3 = Object.create(obj1);
        console.log(obj3.__proto__ === obj1); // true
        console.log(obj3.id); // 1
複製代碼

完整代碼:

function new2(MyFun, ...list) {
				let o = Object.create(MyFun.prototype);
				let k = MyFun.call(o, ...list);
				return typeof k === 'object' ? k : o;
			}

			function Car(color, name) {
				this.color = color;
				this.name = name;
				return "new car";
			}
			
			Car.prototype.fun=function(){
				console.log(this.color,this.name)
			}
			
			var obj=new2(Car,123,'小花');
			console.log(obj)
			console.log(obj.__proto__===Car.prototype);
			console.log(Car.prototype.isPrototypeOf(obj))
			console.log(Object.prototype.isPrototypeOf(obj))
			console.log(obj instanceof Car)
			console.log(obj.constructor===Car)
複製代碼

有什麼問題?

  • typeof k === 'object' 若是k爲null怎麼辦?
  • MyFun傳null,undefined怎麼辦?
function new2(MyFun, ...list) {
				if(!MyFun)  throw new Error("第一個參數必須是函數");
				let o = Object.create(MyFun.prototype);
				let k = MyFun.call(o, ...list);
				return k&&(typeof k === 'object') ? k : o;
			}

			function Car(color, name) {
				this.color = color;
				this.name = name;
				return null;
			}
			
			Car.prototype.fun=function(){
				console.log(this.color,this.name)
			}
		
			var obj=new2(Car,123,'小花');
			console.log(obj)
			console.log(obj.__proto__===Car.prototype);
			console.log(Car.prototype.isPrototypeOf(obj))
			console.log(Object.prototype.isPrototypeOf(obj))
			console.log(obj instanceof Car)
			console.log(obj.constructor===Car);
	
			var obj=new2(null,123,'小花');
複製代碼
相關文章
相關標籤/搜索