主要内容
通过代码完成需求,逐步优化代码,提高代码性能,减少内存占用。最终理解构造函数的使用方法、new操作符的运行机制
需求1
- 正方形边长为5,求面积、长度属性
let square = { 创建需求对象
width:5, 长度属性
get Area(){ return this.width*this.width }, 面积函数
get Length(){ return this.width*4} 周长函数
}
需求2
- 多个正方形,长度为5,求面积、长度属性
- 方法1
get square1={
width:5,
get Area(){ return this.width*this.width}, 第一个
get Length(){ return this.width*4}
get square2={
width:5,
get Area(){ return this.width*this.width}, 第二个
get Length(){ return this.width*4}
.
.
.
.
get squaren={
width:5,
get Area(){.................. } 第n个
get Length(){.................}
缺点:繁琐,比较傻
- 方法2
let squareList=[ ] 定义数组(由square对象组成)
for(let i=0,i<12,i++){ 循环控制条件(12次)
squareList[i]={ 调用第i个对象
width:5, 对象宽度属性
getArea(){return this.width*this.width}, 对象面积属性
getLength(){ return this.width*4} 对象周长属性
}
需求变化: 边长不全是5,例如5,6,5,6,5,6,5,6,5
let squareList=[] 定义数组(由square对象组成)
let widthList=[5,6,5,6,5,6,5,6,5,6,5,6] 定义边长,width数组
for(let i=0,i<12,i++){ 循环控制条件,循环12次
squareList[i]={ 调用squareList数组第i项对象
width:widthList[i], 调用边长width数组第i项
getArea(){ return this.width*this.width}, 面积属性
getLength(){ renturn this.width*4} 周长属性
}
缺点:占用内存
内存调用机制分析
每新生成一个square对象,就新生成面积和周长函数并由square内的相关属性调用,两个函数不可重复调用,只能重复地新生成,被新的square内的属性调用
- 方法3:借助原型
- 思路:将12个对象的共有属性放到原型里面
let suqareList=[] 创建square对象组成的数组
let width list=[5,6,5,6,5,6,5,6,5,6,5,6] 创建边长数组
let squarePrototype={ 创建由共有属性组成的对象
getArea(){return this.width*this.width}
getLength(){ return this.width*4}
}
for(let i=0,i<12,i++){ 循环条件,循环12次
squareList[i]=Object.creat(squarePrototupe) 在square对象原型内加入共有属性
squareList[i].width=widthList[i] 在square对象内加入width属性
}
思路:将对象square的共有属性加进原型内,避免重复生成函数
缺点:创建square的代码太分散了
- 方法4:把代码抽离到一个函数里,然后调用函数
let squareList=[]
let widthList=[5,6,5,6,5,6,5,6,5,6,5,6]
function creatSquare(width){ 构造函数
let obj=Object.creat(squarePrototype) 构造空对象obj,其原型里面加入square的共有属性
obj.width=width obj的width属性就是square的width属性
return obj 返回obj对象
}
let squarePrototype = { 申明square的共有属性组成的对象
getArea(){ return this.width * this.width },
getLength(){ return this.width * 4 }
}
for(let i=0,i<12,i++){ 循环条件
squareList[i] = createSquare(widthList[i]) 对象squareList调用构造函数(见第三行)
}
缺点:squarePrototype 原型和createSquar函数还是分散的
- 方法5:**把原型直接放到构造函数里面
let squareList = []
let widthList = [5,6,5,6,5,6,5,6,5,6,5,6]
function createSquare(width){ 构造函数
let obj = Object.create(createSquare.squarePrototype) 将square共有属性直接加入函数原型中
obj.width = width
return obj
}
此时的函数不执行,只有在最终函数被调用的时候才会运行,此块代码与下方代码设置顺序不影响
createSquare.squarePrototype = {
getArea(){ 定义函数里面square共有属性中的具体内容
return this.width * this.width
},
getLength(){
return this.width * 4
},
constructor: createSquare 方便通过原型找到构造函数
}
for(let i = 0; i<12; i++){
squareList[i] = createSquare(widthList[i]) square直接调用函数里面的width
console.log(squareList[i].constructor) 通过square里面的constructor找到构造函数
}
-- 重构代码
let squareList = []
let widthList = [5,6,5,6,5,6,5,6,5,6,5,6]
function Square(width){
this.width = width
}
Square.prototype.getArea = function(){
return this.width * this.width
}
Square.prototype.getLength = function(){
return this.width * 4
}
for(let i = 0; i<12; i++){
squareList[i] = new Square(widthList[i])
console.log(squareList[i].constructor)
}
每个函数都有 prototype 属性
每个 prototype 都有 constructor 属性
new操作符
对比代码
function createSquare(width){
let obj = Object.create(createSquare.squarePrototype)
obj.width = width
return obj
}
createSquare.squarePrototype = {
getArea(){
return this.width * this.width
},
getLength(){
return this.width * 4
},
constructor: createSquare
}
let square = createSquare(5)
最终简化版:引入new操作符
function Square(width){
this.width = width 自身属性有宽度
}
Square.prototype.getArea = function(){ 共有属性 面积函数
return this.width * this.width
}
Square.prototype.getLength = function(){ 共有属性 周长函数
return this.width * 4
}
let square = new Square(5)
最基本结构案例
new操作符总结
new X() 自动做了四件事情
- 自动创建空对象
- 自动为空对象关联原型,原型地址为X.prototype
- 自动将空对象作为this关键字进行构造函数
- 自动return this
构造函数X
- X本身负责给对象本身添加属性
- X.prtotype对象负责保存对象的共同属性
代码规范
代码规范
- 所有构造函数(专门用于创建对象的函数)首字母大写
- 所有被构造出来的对象,首字母小写
词性
- new 后面的函数,使用名词形式
- 如 new Person()、new Object()
- 其他函数,一般使用动词开头
- 如 createSquare(5)、createElement('div')