前言
咱们在深刻浅出面向对象和原型【概念篇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()的语法糖