我們可以一起通過代碼實現(xiàn)來看看new關(guān)鍵字到底做了一些什么事情
function Book(name) {
this.name = name;
}
Book.prototype.say = function() {
console.log(this.name);
};
let book = new Book('javascript高級程序設(shè)計');
console.log(book);
book.say();
輸出結(jié)果如下圖:

new操作符實例化構(gòu)造函數(shù)
上例中,new關(guān)鍵字調(diào)用的構(gòu)造函數(shù)并沒有任何返回值,最終我們實例創(chuàng)建了一個對象,那如果構(gòu)造函數(shù)擁有返回值呢?new關(guān)鍵字會如何處理
function Test(name) {
this.conname = name;
return 1
}
Test.prototype.say = function() {
console.log(this.conname);
};
let test = new Test('測試');
console.log(test);
test.say();

new操作符對于擁有返回值的構(gòu)造函數(shù)
上例中,構(gòu)造函數(shù)返回了一個基本數(shù)據(jù)類型的值,而最終我們依舊拿到了想要的實例對象。那如果構(gòu)造函數(shù)返回一個引用類型的值呢?
function Test(name) {
this.conname = name;
return {
name
}
}
Test.prototype.say = function() {
console.log(this.conname);
};
let test = new Test('測試');
console.log(test);
test.say();
上例中,構(gòu)造函數(shù)最終返回了一個對象,這個對象上有name屬性,然后在構(gòu)造函數(shù)的prototype上,還擁有say方法,我們看看這次new得到的值是什么,是否擁有構(gòu)造函數(shù)prototype上的方法

new操作符對于擁有返回值的構(gòu)造函數(shù)
可以看到的是,我們拿到的對象是最終構(gòu)造函數(shù)return出來的那個對象,而這個對象并沒有構(gòu)造函數(shù)prototype上的say方法
經(jīng)過測試,我們發(fā)現(xiàn)
- new關(guān)鍵字 通過構(gòu)造函數(shù)創(chuàng)建出來的實例可以訪問到構(gòu)造函數(shù)中的屬性
- new關(guān)鍵字 通過構(gòu)造函數(shù)創(chuàng)建出來的實例可以訪問到構(gòu)造函數(shù)原型鏈中的屬性,也就是說通過 new 操作符,實例與構(gòu)造函數(shù)通過原型鏈連接了起來
- new關(guān)鍵字 操作的構(gòu)造函數(shù)如果返回基本類型,那么這個返回值毫無意義
- new關(guān)鍵字 操作的構(gòu)造函數(shù)如果返回引用類型,那么這個返回值會被正常使用
通過上述的一些測試,我們可以自己試著實現(xiàn)一下new關(guān)鍵字;
function Book(name) {
this.name = name;
}
Book.prototype.say = function() {
console.log(this.name);
};
function myNew(Constructor, ...args) {
let obj = {};
obj.__proto__ = Constructor.prototype;
let result = Constructor.call(obj, ...args);
return result instanceof Object ? result : obj;
}
let book = myNew(Book, 'javascript高級程序設(shè)計');
console.log(book);
book.say();

自己實現(xiàn)new關(guān)鍵字
總結(jié) new關(guān)鍵字到底做了些什么
- 先創(chuàng)建了一個新的空對象
- 然后讓這個空對象的proto指向函數(shù)的原型prototype
- 將對象作為函數(shù)的this傳進(jìn)去,如果return 出來東西是對象的話就直接返回 return 的內(nèi)容,沒有的話就返回創(chuàng)建的這個對象