前言
咱們在深刻淺出面向對象和原型【概念篇2】在這篇文章中瞭解到瞭如何使用new Function解決重複建立浪費內存的問題,其中的關鍵就是new,那麼這篇文章讓咱們來從新瞭解new的前世此生編程
一個苦逼年級主任的故事
開學啦~~~高一年級主任龔主任須要爲整年級每一位理科班新生錄入學號併爲每一位學生生成相關檔案
不只要本身留一份並且要把每個檔案都上傳到學校資料庫
哇,整年級一千個學生,一個個輸入,不要命啦?
還好龔主任學過編程segmentfault
// 先造一個對象,把相關數據都先寫進去,看看是啥樣的 var 學生 = { 學號: 1, 年級: '高一', 所選方向: '理科班', 上傳資料: function () {/*上傳資料的代碼*/ } } // 不錯,檔案大體就是如此 // 再來個數組本身留着做爲備份 // 那麼循環一千次吧 var 整年級學生 = [] for (var i = 0; i < 1000; i++) { var 學生 = { 學號: i, 年級: '高一', 所選方向: '理科班', 上傳資料: function () {/*上傳資料的代碼*/} } 整年級學生.push(學生) }
龔主任忽然想到,他昨天晚上在纔在segmentfault上看到有關於內存浪費的文章——深刻淺出面向對象和原型【概念篇2】
那麼他寫的這個代碼就是典型的內存浪費啊
每一個學生除了學號不一樣,其它都相同,咋辦呢?
哎對了,那篇文章說能夠經過原型和原型鏈解決這個問題
那麼試試吧數組
// 先建立一個學生原型,而後把相同的代碼都放在這裏 var 學生原型 = { 年級: '高一', 所選方向: '理科班', 上傳資料: function () {/*上傳資料的代碼*/} } // 從新寫循環代碼 var 整年級學生 = [] for (var i = 0; i < 1000; i++) { var 學生 = { 學號: i } // 還記得嗎,每一個對象自動帶有__proto__屬性 // 不過在這裏__proto__屬性的指向須要咱們本身去設定 學生.__proto__ = 學生原型 整年級學生.push(學生) }
好了,大功告成,這下內存不浪費了
可是,龔主任據說程序猿寫代碼都追求可讀性強,他這寫的太不優雅了
再改改吧函數
// 優雅的代碼離不開封裝,如今讓咱們來封裝封裝吧 function 學生(學號) { // 咱們先創建一個臨時對象,把例如學號之類須要改變的屬性放進去 var 臨時對象 = {} 臨時對象.學號 = 學號 // 再把臨時對象的__proto__手工綁定到學生.原型 臨時對象.__proto__ = 學生.原型 return 臨時對象 } 學生.原型 = { 年級: '高一', 所選方向: '理科班', 上傳資料: function () {/*上傳資料的代碼*/ } } // 好了,開始循環吧 var 學生們 = [] for (var i = 0; i < 1000; i++) { 學生們.push(學生(i)) }
好了,讓咱們先遠離一下龔先生和他的代碼,來看看到底什麼是new
function 學生(學號) { // 咱們先創建一個臨時對象,把例如學號之類須要改變的屬性放進去 // 【new作的第一件事:幫你創立一個臨時對象,臨時對象經過this訪問】 var 臨時對象 = {} 臨時對象.學號 = 學號 // 再把臨時對象的__proto__手工綁定到學生原型 // 【new作的第二件事:幫你自動把__proto__綁定到學生.原型】 臨時對象.__proto__ = 學生.原型 // 【new作的第三件事:幫你return臨時對象】 return 臨時對象 } // 【但new只有一個要求:把學生原型更名爲 學生.prototype】 學生.原型 = { 年級: '高一', 所選方向: '理科班', 上傳資料: function () {/*上傳資料的代碼*/} }
那麼,咱們用new該怎麼寫?so easy。new幫你作的事,你還本身作它幹嗎呢?
function 學生(學號) { // 【new作的第一件事:幫你創立一個臨時對象,臨時對象經過this訪問】 // 因此咱們不用建立臨時對象了,把下面那行代碼註釋掉 // var 臨時對象 = {} // 把臨時對象都改成this就好 this.學號 = 學號 // 再把臨時對象的__proto__手工綁定到學生原型 // 【new作的第二件事:幫你自動把__proto__綁定到學生原型】 // 咱們不用手動綁定了,註釋掉 // 臨時對象.__proto__ = 學生原型 // 【new作的第三件事:幫你return臨時對象】 // 咱們不用手動return了,註釋掉 // return 臨時對象 } // 【但new只有一個要求:把學生原型更名爲 學生.prototype】 // new 幫了咱們這麼多忙,按照他的意思來唄,改了! 學生.prototype = { 年級: '高一', 所選方向: '理科班', 上傳資料: function () {/*上傳資料的代碼*/} } var 學生們 = [] for (var i = 0; i < 1000; i++) { 學生們.push(new 學生(i))
個人天哪,咱們的代碼居然經過new減小了這麼多!!
function test(id) { this.id = id } new test(1) console.log(test.prototype) // {constructor: ƒ}
使用new操做符的時候,爲了記錄臨時對象是由哪一個函數建立的,會在prototype裏添加一個constructor屬性,指向建立臨時對象的函數
注意:若是直接給prototype賦值,則constructor屬性會消失this
function 學生(學號) { this.學號 = 學號 } 學生.prototype = { 年級: '高一', 所選方向: '理科班', 上傳資料: function () {/*上傳資料的代碼*/} } var 學生們 = [] for (var i = 0; i < 1000; i++) { 學生們.push(new 學生(i)) } // 沒有出現constructor屬性 console.log(學生.prototype) // {年級: "高一", 所選方向: "理科班", 上傳資料: ƒ}
能夠採用另外一種賦值方式prototype
function 學生(學號) { this.學號 = 學號 } 學生.prototype.年級 = '高一' 學生.prototype.所選方向 = '理科班' 學生.prototype.上傳資料 = function () {/*上傳資料的代碼*/} var 學生們 = [] for (var i = 0; i < 1000; i++) { 學生們.push(new 學生(i)) } // 出現constructor屬性 console.log(學生.prototype) // {年級: "高一", 所選方向: "理科班", 上傳資料: ƒ, constructor: ƒ}
new的本質其實就是一個語法糖,目的就是爲了幫咱們省代碼code
var a = {} 是 var a = new Object()的語法糖 var a = [] 是 var a = new Array()的語法糖 var a = funciton(){} 是 var a = new Function()的語法糖