引入原型对象:彻底解决内存浪费 + 变量污染

536 阅读3分钟

当我们需要创建很多个对象 (姓名、年龄、性别)时 ,我们需要封装函数以解决代码冗余的问题,为了更高效,我们常使用构造函数来创建对象.

不妨先比较以下几种不同方法的优劣

1.三种方法的优劣

1.1构造函数内部方法:存在浪费内存的问题

function Person(name,age){
        //(1)创建空对象   {}
        //(2)this指向这个对象  this={}
        //(3)对象赋值
       this.name = name
       this.age = age
       this.eat = function(){
         console.log('逍遥法外')
       }
        //(4)返回这个对象  return this
}
let p1 = new Person('罗翔', 50)
let p2 = new Person('张三', 28)
console.log(p1.eat == p2.eat)  //结果是?-----------------false

p1和p2都有eat方法且代码一致,但他们是同一个方法吗?

不是. 看看下面这张图,很好理解:内存中值类型存在中,而引用类型存在里,p1和p2的eat虽然代码是一致的,但是它们两个函数在堆中是两个不同的堆地址,也就是说通过构造函数内部方法,会存在浪费内存的问题.

构造函数内部方法2.png

1.2 使用全局函数:解决内存浪费

使用全局函数,即在全局范围内定义多个函数

显然,函数太多,一旦涉及到团队合作的项目,大概率造成变量污染.

1.3 使用对象 : 解决内存浪费 + 变量污染的问题

上述两种方法都有很大的局限性,于是我们想到通过对象来封装函数

const obj = {
      happy: function () {
        console.log('逍遥法外')
      },
      learn: function () {
        console.log('学习')
      }
    }
​
    function Person(name, age) {
      this.name = name
      this.age = age
      this.eat = obj.eat
      this.learn = obj.learn
    }
​
    let p1 = new Person('罗翔', 50)
    let p2 = new Person('张三', 28)
​
    console.log(p1, p2)
   
    console.log(p1.happy == p2.happy)//true

构造函数内部方法.png 此时p1的happy函数和p2的happy函数终于指向同一个函数,不同项目之间变量污染问题发生的概率大大降低.

但是,凡事都有但是.........

“ Wer mit Ungeheuern kämpft, mag zusehn, dass er nicht dabei zum Ungeheuer wird. Und wenn du lange in einen Abgrund blickst, blickt der Abgrund auch in dich hinein. 与恶龙缠斗过久,自身亦成为恶龙; 凝视深渊过久,深渊将回以凝视。 ” ——Friedrich Wilhelm Nietzsche 弗里德里希·威廉·尼采

使用对象封装函数这种方式解决了内存浪费和变量污染的问题,但也因此,对象本身也成了唯一的污染.

2. 使用原型对象,彻底解决内存浪费 + 变量污染

千呼万唤始出来,通过对原型对象的使用,我们得以彻底解决内存浪费 + 变量污染的问题

        //1.构造函数
        function Person(name,age){
          this.name = name
          this.age = age
        }
​
        //2.原型对象
        Person.prototype.happy = function(){
          console.log('逍遥法外')
        }
​
        Person.prototype.learn = function(){
          console.log('学习')
        }
​
        //3.实例对象
        let p1 = new Person('罗翔',50)
        let p2 = new Person('张三',28)
​
        console.log(p1,p2)
​
        p1.happy()
​
        p2.learn()

其中:

prototype : 属于构造函数,指向原型对象

  • 作用: 解决构造函数内存浪费+变量污染

proto : 属于实例对象,指向原型对象

  • 作用: 让实例对象直接使用原型的成员(函数+属性)

constructor : 属于原型对象,指向构造函数

  • 作用 : 让实例对象知道自己的构造函数是谁

三者关系png.png