万物皆对象
1. 原型
- 每个函数都有
ptototype
属性;每个引用类型都有__proto__
属性; prototype === __proto__
,它俩的属性值都指向构造函数的原型;
console.dir({})
console.dir([])
function fn() {}
console.dir(fn);
console.log(fn.__proto__ === Function.prototype); // true
2. 原型链
当访问一个对象的某个属性时,会现在这个对象内部属性查找;如果没有找到,则在它的__proto__
隐式原型上查找,即它的构造函数的prototype
;如果还没找到就在构造函数的prototype的__proto__
中查找,这种一层一层向上查找形成的链式结构就是原型链。
结果:直到查到或Object.prototype.__proto__ === null
3. 原型的作用
- 数据共享,减少内存空间
- 实现继承
1.数据共享
function Animal(name) {
this.name = name;
this.eat = function () {
console.log(this.name + '在吃东西');
}
}
// 每实例化一个对象时,都会给这个对象的eat()方法开闭内存空间,实例化对象多了就会浪费内存空间
var dog = new Animal('小狗')
dog.eat() // 小狗在吃东西
console.dir(dog)
var cat = new Animal('小猫')
cat.eat() // 小猫在吃东西
console.dir(cat)
每次实例化一个对象时,都会给eat()方法开辟一个内存空间;当实例化对象多了,就会造成内存浪费。
在构造函数的原型上添加方法可实现数据共享(不能使用箭头函数,this指向问题)
function Animal(name) {
this.name = name
}
// 在构造函数的原型上添加方法,可实现数据共享(不能使用箭头函数,this指向问题)
// Animal.prototype.eat = ()=> {
// console.log(this.name + '在吃东西');
// }
Animal.prototype.eat = function () {
console.log(this.name + '在吃东西');
}
var dog = new Animal('小狗')
dog.eat() // 小狗在吃东西
console.dir(dog)
var cat = new Animal('小猫')
cat.eat()
console.dir(cat)
2.改变构造函数的原型的指向,可实现继承
function Fool(name) {
this.name = name
}
Fool.prototype.eat = function () {
console.log(this.name + '很好吃');
}
function Appel(color) {
this.color = color
}
// 使用原型实现继承
Appel.prototype = new Fool('红苹果') // Appel构造函数的原型指向Fool的实例化对象
var appel = new Appel()
appel.eat() // 红苹果很好吃