new 運算符建立一個用戶定義的對象類型的實例或具備構造函數的內置對象的實例。
這是MDN上對new操做符的定義,從這句話中能夠看出new返回的其實就是一個實例,那麼問題來了實例又是個啥東西?javascript
先看個例子:java
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__
一直向上查找。segmentfault
相關:簡單說說原型和原型鏈app
那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);
這句代碼有疑問。this
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會發現貌似沒有問題,能夠正常運行。但是當咱們稍稍修改一下上述代碼就會發現運行結果會不同。prototype
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操做符應該返回的對象是構造函數裏面的返回值(僅當返回值是對象時有效)。
修改以前的代碼。code
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上的描述:對象
- 建立一個空的簡單JavaScript對象(即{});
- 連接該對象(即設置該對象的構造函數)到另外一個對象 ;
- 將步驟1新建立的對象做爲this的上下文 ;
- 若是該函數沒有返回對象,則返回this。