面向对象概念
面向对象是一种思想,是基于面向过程而言的。
利用构造函数创建对象
- 假如我们把王者荣耀里面的英雄看成一个对象,那王者荣耀英雄有很多不同的属性,比如有名字、攻击类型等等。
利用构造函数的方法封装
function Hero (name,type) { // 构造函数
this.name = name;
this.type = type;
}
利用构造函数可以生成实例对象,就是在调用函数
var houyi = new Hero ('后羿','射手型')
var lianpo = new Hero ('廉颇','坦克型')
new在执行时会做四件事
- 在内存中创建了一个新的空对象
- 让this指向这个对象
- 执行构造函数里面的代码,给这个对象添加新的属性和方法
- 返回这个this对象(所以构造函数内部不需要return)
这时 houyi 和 lianpo 会有一个共同的 constructor 属性 ,这个属性返回的就是这个构造函数。
console.log(houyi.constructor);
// ƒ Hero(name, type) { // 构造函数
this.name = name;
this.type = type;
}
console.log(lianpo.constructor);
// ƒ Hero(name, type) { // 构造函数
this.name = name;
this.type = type;
}
这样的确很方便,但是有一个问题,那就是浪费内存。
如果我们向构造函数里添加一个不变的属性和方法。
添加一个方法构造函数如下
function Hero (name,type,dazhao) { // 构造函数
this.name = name;
this.type = type;
this.dazhao = dazhao;
}
// 生成两个实例
var houyi = new Hero ('后羿','射手型',function () {
console.log('后羿射日')
})
var lianpo = new Hero ('廉颇','坦克型',function () {
console.log('后羿射日')
})
但是这两个一模一样的函数会在内存中占用两个空间。
console.log(houyi.dazhao === lianpo.dazhao) // false
要解决这个办法其实可以在全局中定义函数
// 在全局中定义函数
var a = function () {
consloe.log('后羿射日')
}
function Hero (name,type,dazhao) { // 构造函数
this.name = name;
this.type = type;
this.dazhao = dazhao;
}
// 生成两个实例
var houyi = new Hero ('后羿','射手型',a)
var lianpo = new Hero ('廉颇','坦克型',a)
console.log(houyi.dazhao === lianpo.dazhao) // true
全局定义虽然可以解决这个问题,但是在全局中定义的变量或者函数很容易被覆盖。这显然也不是最优解。
但是,任何一个对象天生自带一个__ proto__属性,这个东西是一个对象,叫做原型对象。
对象是可以访问到原型上的属性和方法。
任何一个函数都有一个prototype属性,这个也是一个对象,叫做原型对象。这个对象里面的属性和方法是可以被构造函数的实例继承。
这就说明我们可以把这些不变的属性和方法直接定义到prototype这个对象上。
function Hero (name,type) { // 构造函数
this.name = name;
this.type = type;
}
Hero.prototype.dazhao = function () {
console.log('后羿射日')
}
// 然后生成实例
var houyi = new Hero ('后羿','射手型')
var lianpo = new Hero ('廉颇','坦克型')
houyi.dazhao() // 后羿射日
console.log(houyi.dazhao === lianpo.dazhao) // true
这样所有实例的 dazhao 属性,其实都是同一个内存地址了,指向了prototype对象,也解决了全局定义容易被覆盖的问题。