JS 对象分类

116 阅读3分钟

计算正方形周长面积代码优化

let squareList=[];

let widthList=[1,2,5,7,9,1,2,3,4,5,6,7];

for(let i=0;i < 11;i++){

    squareList[i]={
        width:widthList[i],
        getArea(){
            return this.width*this.width
        },
        getLength(){
            return this.width*4
        }
    }
}

内存浪费分析:for循环里i一直在变,在栈里改变,对于空数组,从第0->11个,必须新生成一块内存,其中的两个函数每次需要新生成,造成重复内存太多

image.png

借助原型

此时squareList.__proto__.__proto__===Object.prototype

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) 
  squareList[i].width = widthList[i]
}

函数和原型结合

封装:把细节写到一个函数中去

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)
}

new操作符

规定好的,每个js函数有prototype属性,里面存在constructor

  1. new X()做了那几件事
  • 自动创建新对象,此时是空对象
  • 自动将空对象关联他的原型,指定为X.prototype
  • 将空对象作为this关键字运行构造函数
  • 自动返回return this
  1. 构造函数X做了哪2件事
  • X函数给自己添加自身属性
  • X.prototype对用于保存对象的共有属性

公式

你是谁构造的,你的原型就是谁的prototype对应的对象

对象.__proto__===其构造函数的.prototype

测试题:

  1. let x = {},请问:x 的原型是什么?x.__proto__ 的值是什么?

原型是:Object.Prototype的对象

x.__proto__ 的值也是Object.Prototype

30e880a3684e864d7af0ef1b4edaa68.jpg

2.png

问x的原型就是在问x.__proto__ 的值

2.let square = new Square(5),请问:square 的原型是什么?square.__proto__ 的值是什么?

square 的原型就是square.__proto__ 的值:Square.prototype

  1. Object.prototype 是哪个函数构造出来的?Object.prototype 的原型是什么?Object.prototype.__proto__的值是什么?

Object.prototype 的原型没有原型,Object.prototype.__proto__的值被强行设置为null

特殊值:Object.prototype是由哪个函数构造的:

他没有爸爸妈妈,没有原型,Object.prototype.__proto__为null,他只是个简单对象而已 内存图:window里有个Object属性,存着一个地址,这个地址对应window.Object的值,里面有prototype属性,对应原型的地址

构造函数算圆的周长面积

function Cricle(radius){
    this.radius=radius
}

Cricle.prototype.getArea=function(){
    return Math.pow(this.radius,2)*Math.PI}
    
Cricle.prototype.getLength=function(){
    return 2*this.radius*Math.PI}
    
let x=new Cricle(5)

x.getArea()
78.53981633974483

x.getLength()
31.41592653589793

终极一问

  • window是Window构造的 ,可以通过constructor属性看出构造者
  • window.Object是window.Function构造的
  • window.Function是window.Function构造的,浏览器构造了Function,然后指定它的构造者是自己
  1. 关于prototype属性
  • 所有函数一出生就有一个prototype属性(除了箭头函数)
  • 所有prototype一出生就有一个consrtuctor属性
  • 所有constructor属性一出生就保存了对应的函数的地址
  • 如果一个函数不是构造函数,它依然拥有prototype属性,只不过这个属性没什么用
  • 如果一个对象不是函数,那么这个对象一般来说没有prototype属性,但这个对象一般一定会有__proto__属性
  1. Object.prototye 是「Object 构造出来的对象 obj」的原型,即 obj.__proto__ === Object.prototype
  2. Object.__proto__ 是 Object 的原型,由于 Object 是函数,而所有函数的原型都是 Function.prototype,所以Object.__proto__=== Function.prototype
  3. Object.prototye 不是 Object 的原型,Object.__proto__ 才是 Object 的原型(x.原型 等价于 x.__proto__

代码题

  1. 原型方法实现:
function Person(你来补全代码){
    你来补全代码
}

let person = new Person('frank', 18)
person.name === 'frank' // true
person.age === 18 // true
person.sayHi() // 打印出「你好,我叫 frank」

let person2 = new Person('jack', 19)
person2.name === 'jack' // true
person2.age === 19 // true
person2.sayHi() // 打印出「你好,我叫 jack」

思路先构造函数,再用this加自身即新对象属性,对原型加共有属性,常为函数

function Person(name,age){
    this.name=name
    this.age=age
}
Person.prototype.sayHi=function(){
    console.log('你好,我是'+this.name)
}
let person = new Person('frank', 18)
  1. class方法实现: 相对于原型方法,直接在constructor里加自身属性,在函数外创建函数对象
class Person{
    constructor(name, age){
        this.name = name
        this.age = age
    }
    sayHi(){
        console.log('你好,我是'+this.name)
    }
}

x.__proto__ X.prototype都存的是原型的地址,对象就是原型。共有属性的集合就是原型。

image.png