前言
我們在深入淺出面向對象和原型【概念篇2】在這篇文章中了解到了如何使用new Function解決重復創建浪費內存的問題,其中的關鍵就是new,那么這篇文章讓我們來重新了解new的前世今生
一個苦逼年級主任的故事
開學啦~~~高一年級主任龔主任需要為全年級每一位理科班新生錄入學號并為每一位學生生成相關檔案
不僅要自己留一份而且要把每一個檔案都上傳到學校資料庫
哇,全年級一千個學生,一個個輸入,不要命啦?
還好龔主任學過編程
// 先造一個對象,把相關數據都先寫進去,看看是啥樣的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減少了這么多!!
constructor屬性
function test(id) {this.id = id}new test(1)console.log(test.prototype) // {constructor: ?}
使用new操作符的時候,為了記錄臨時對象是由哪個函數創建的,會在prototype里添加一個constructor屬性,指向創建臨時對象的函數
注意:如果直接給prototype賦值,則constructor屬性會消失
function 學生(學號) {this.學號 = 學號}學生.prototype = {年級: '高一',所選方向: '理科班',上傳資料: function () {/*上傳資料的代碼*/}}var 學生們 = []for (var i = 0; i < 1000; i++) {學生們.push(new 學生(i))}// 沒有出現constructor屬性console.log(學生.prototype) // {年級: "高一", 所選方向: "理科班", 上傳資料: ?}
可以采用另一種賦值方式
function 學生(學號) {this.學號 = 學號}學生.prototype.年級 = '高一'學生.prototype.所選方向 = '理科班'學生.prototype.上傳資料 = function () {/*上傳資料的代碼*/}var 學生們 = []for (var i = 0; i < 1000; i++) {學生們.push(new 學生(i))}// 出現constructor屬性console.log(學生.prototype) // {年級: "高一", 所選方向: "理科班", 上傳資料: ?, constructor: ?}
總結
new的本質
new的本質其實就是一個語法糖,目的就是為了幫我們省代碼
new的作用
創立一個臨時對象,臨時對象指向類的this把實例__proto__綁定到類的prototypereturn臨時對象(也就是this)關于new的語法糖
var a = {} 是 var a = new Object()的語法糖
var a = [] 是 var a = new Array()的語法糖
var a = funciton(){} 是 var a = new Function()的語法糖
參考
new運算符
JS 的 new 到底是干什么的?
總結
以上是生活随笔為你收集整理的深入浅出面向对象和原型【番外篇——重新认识new】的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。