当我们需要创建很多个对象 (姓名、年龄、性别)时 ,我们需要封装函数以解决代码冗余的问题,为了更高效,我们常使用构造函数来创建对象.
不妨先比较以下几种不同方法的优劣
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虽然代码是一致的,但是它们两个函数在堆中是两个不同的堆地址,也就是说通过构造函数内部方法,会存在浪费内存的问题.
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
此时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 : 属于原型对象,指向构造函数
- 作用 : 让实例对象知道自己的构造函数是谁