输出正方形的面积和周长
第一版
let squareList = []
let widthList = [5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6]
for (let i = 0; i < 12; i++) {
squareList[i] = {
width: widthList[i],
getArea() {
return this.width * this.width
},
getLength() {
return this.width * 4
}
}
}
//浪费了太多内存
第二版
let squareList = []
let widthList = [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++) {
squareList[i] = Object.create(squarePrototype)//创建一个对象,对象的原型是squarePrototype
squareList[i].width = widthList[i]
}
//创建square的代码太分散了
第三版
let squareList = []
let widthList = [5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6]
//封装,函数它也是一个对象,所以如果我们把原型放到函数上,
function createSquare(width) {//此函数叫做构造函数,因为这个函数它能够构造出一个对象出来
let obj = Object.create(squarePrototype)//以squarePrototype为原型创建空对象
obj.width = width
return obj
}
//原型
let squarePrototype = {
getArea(){
return this.width * this.width
},
getLength(){
return this.width * 4
}
}
for(let i=0;i<12;i++){
squareList[i] = createSquare(widthList[i])
}
//squarePrototype原型和createSquare函数还是分散的,能不能组合在一起
第四版
/**
* 函数和原型结合
*/
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)
obj.width = width
return obj
}
createSquare.squarePrototype = {
//把原型放到函数上,结合够紧密
getArea(){
return this.width * this.width
},
getLength() {
return this.width * 4
},
constructor: createSquare //方便通过原型找到构造函数
}
for(let i=0;i<12;i++) {
squareList[i] = createSquare(widthList[i])
console.log(squareList[i].constructor)
}
console.log('squareList',squareList)
函数是对象
最终版,使用new操作符
所有的js里面的函数,从它出生的时候就自带一个prototype的属性,这个属性从它出生的时候就有一个constructor,这个constructor从它出生的时候,它的值就是函数自身
/**
* 函数和原型结合(重写)
*/
let squareList = []
let widthList = [5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6]
function Square(width) {
this.width = width//用this代表新的对象,就是obj
// return obj;//不用写,它会帮你写
}
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 X()自动做了四件事情
- 自动创建空对象
- 自动为空对象关联原型,原型地址指定为X.prototype(自动将该空对象的原型指向 X.prototype(即将 X.prototype 保存的地址复制到空对象.__proto__ 里))
- 自动将空对象作为this关键字运行构造函数
- 自动return this
构造函数X
- X函数本身负责给对象本身添加属性
- X.prototype对象负责保存对象的共用属性
原型与公用属性的关系
结论: 你是谁构造的,你的原型就是谁的prototype属性对应的对象
原型公式: 对象.proto === 其构造函数.prototype
square的原型是什么 等价于 square.proto 的值是什么
x 均代表普通对象
- 「x 的原型」等价于「x._proto_ 所指的对象」 ,有时为了方便,我们可以认为「x 的原型」等价于「x._proto_ 」
- 一个对象的原型指的是这个对象与其他同类对象的公有属性的集合,比如 obj1 和 ob2 同时拥有 toString / valueOf,那么 toString / valueOf 等属性组成的对象,就是 obj1 和 obj2 的原型,这个原型的地址一般储存在构造函数的 prototype 里
- x.__proto__和 Object.prototype 存储着同一个对象的地址,这个对象就是 x 的原型
- 每个对象都有原型,但除了「根对象 Object.prototype」比较特殊,Object.prototype 这个对象的原型为空 null
prototype属性
- 所有函数一出生就有一个 prototype 属性(除了箭头函数)
- 所有 prototype 一出生就有一个 constructor 属性
- 所有 constructor 属性一出生就保存了对应的函数的地址
- 如果一个函数不是构造函数,它依然拥有 prototype 属性,只不过这个属性暂时没什么用
- 如果一个对象不是函数,那么这个对象一般来说没有 prototype 属性,但这个对象一般一定会有 _proto_ 属性
注意
- window.Object 是一个函数对象,那么这个「函数对象」的构造函数是Function
- window.Function 是一个函数对象,那么这个「函数对象」的构造函数是Function
- window.Object 是一个函数对象,那么这个「函数对象」的
__proto__是Function.prototype - window.Function 是一个函数对象,那么这个「函数对象」的
__proto__是Function.prototype - window是Window构造的,可以通过constructor属性看出构造者
- 所有函数都是 window.Function 构造的
关于 Object.prototype
- Object.prototye 是「Object 构造出来的对象 obj」的原型,即 obj.__proto__ === Object.prototype
- Object._proto_ 是 Object 的原型,由于 Object 是函数,而所有函数的原型都是 Function.prototype,所以 Object._proto_ === Function.prototype
- Object.prototye 不是 Object 的原型,Object.__proto__ 才是 Object 的原型(「x.原型 等价于 x._proto_」)
- 所有「函数对象」的「构造函数」都是 Function
结论:你是谁构造的,你的原型就是谁的prototype属性对应的对象
原型公式:对象._proto_ === 其构造函数.prototype
class重写Square
class Square{
static x = 1
width = 0
constructor(width){
this.width = width
}
getArea(){
return this.width * this.width
}
getLength(){
return this.width * 4
}
get area2(){ // 只读属性
return this.width * this.width
}
}
sayHi在原型上(语法定义的)
- 所有定义到class的普通方法,都会被放到对象的原型里面,而不是对象身上
sayHi在对象自己身上(语法定义的)
等价写法:
资料来源:饥人谷