构造函数、原型对象和实例对象的三角关系
-
prototype: 属于构造函数,指向原型对象作用:解决资源浪费+变量污染
-
__proto__: 属于实例对象,指向原型对象作用:可以让实例对象访问原型中的成员
-
constructor: 属于原型对象,指向构造函数作用:可以让实例对象 知道自己被哪一个构造函数创建的
<script>
//1.◆构造函数
function Person(name, age) {
this.name = name
this.age = age
}
//2.◆原型对象
Person.prototype.eat = function () {
console.log('吃东西')
}
//3.◆实例对象
let p1 = new Person('大女儿', 5)
//4.◆检查原型 :
//(1)先通过实例对象找构造函数
console.log(p1.__proto__.constructor) //[Function: Person]
//(2)构造函数和原型对象一一对应关系
console.log(p1.__proto__ === Person.prototype)//true
</script>
原型使用注意点
-
哪些属性可以放在构造函数中?
名字、年龄、性别、分数每个对象都不同,所以放入构造函中
-
哪些属性可以放在原型中?
所有实例对象共有的成员(方法等)
-
对象访问原型的规则 : 就近原则
对象访问成员的时候,优先访问自身的。 如果自身没有才会访问原型的
<script>
//◆构造函数
function Person(name, age) {
this.name = name
this.age = age
}
//◆原型对象
//所有的人都是哺乳动物,所以 type 可以放在原型中
Person.prototype.type = '哺乳动物'
//每一个人都可以吃东西,这个方法是大家共有的,就可以放在原型中
Person.prototype.eat = function () {
console.log('吃东西')
}
//◆实例对象
let p1 = new Person('大女儿', 5)
//◆实例对象也可以动态添加属性
p1.type = '大美女'
console.log(p1.type)//大美女
console.log(p1)//Person {name: '大女儿', age: 5, type: '大美女'}
</script>
-
原型是可以覆盖的
实例对象访问覆盖前的原型还是覆盖后的原型,取决于这个实例对象在什么时候创建
- 覆盖前创建 : 实例对象的原型就是覆盖前的原型
- 覆盖后创建 : 实例对象的原型就是覆盖后的原型
<script>
//◆构造函数
function Person(name, age) {
this.name = name
this.age = age
}
//◆原型对象
Person.prototype.eat = function () {
console.log('覆盖前原型-1')
}
//◆实例对象
let p1 = new Person('大女儿', 5)
//◆使用新对象把原来的原型给覆盖掉
Person.prototype = {
eat: function () {
console.log('覆盖后原型-2')
}
}
let p2 = new Person('小女儿', 1)
p1.eat()//覆盖前原型-1
p2.eat()//覆盖后原型-2
</script>
什么是原型链
JavaScript 原型:每个对象都会在其内部初始化一个属性,就是 prototype (原型)
原型链:当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的 prototype,如果还没找到就会在构造函数的 prototype 的 __proto__中查找,这样一层一层向上查找,就会形成一个链式结构,我们称为原型链。