原型定义
是函数function对象的一个属性,它定义了构造函数制造的对象的公共祖先。通过构造函数产生对象,该对象可以继承原型的属性和方法。原型也是对象。
为了更好地理解原型,我们抓住一些关键字;
首先它是函数对象的属性,就比如说函数的name,是一个函数本身就具有的。
定义了构造函数制造的对象的公共祖先,这怎么理解?我们来看段代码:
Person.prototype.name = '钢铁侠'
Person.prototype.say = function () {
console.log('哈哈哈哈')
}
function Person() {
}
let p = new Person()
let p2 = new Person()
console.log(p.name);
console.log(p2.name);
p.say()
此时打印出来三个结果的是'钢铁侠' '钢铁侠' '哈哈哈哈'。也就是构造对象p和p2都继承了函数原型的属性和方法。
原型也是对象,看下图:
图上显示Person.prototype是一个对象{}。
原型特点
1.可以提取公有属性
直接上代码:
Car.prototype = { //不需要在每次创建对象时都执行,降低了代码的耦合度
carName: 'BMW',
height: 1400,
lang: 4900
}
function Car(owner, color) {
this.owner = owner
this.color = color
}
上段代码就直接在函数Car的原型上定义了三个属性,提取了Car的公有属性,每次创建对象都能继承到,这样就降低了代码的耦合度。
2.实例对象无法对原型做 ‘增删改查’
当我们在函数原型上定义了一个属性,构造函数制造出来的对象是无法对原型进行增删改查的。举个改的例子,我们看一下下面代码:
Person.prototype.lastName = '蜘蛛侠'
function Person(name) {
this.name = name
}
var p = new Person('songsong')
p.lastName = 'jiang' //改不动原型的属性
console.log(Person.prototype);
输出的结果是:{ lastName: '蜘蛛侠' },想要修改的话只能通过:Person.prototype.lastName = '超人'来改。
3.实例对象的隐式原型(proto)== 构造函数的显式原型 (prototype)
看到这里就有点抽象,我们直接用代码解释:
Person.prototype.name = 'song'
Person.prototype.age = '18'
function Person() {
}
var person = new Person()
console.log(person.name);
//person.name 先找自己是否具有该属性,没有的话再去 __proto__ 上找
console.log(person.name);
对象都是有原型的,称为隐式原型;函数的原型称为显示原型。实例对象先找自己是否具有该属性,没有的话再去自己的隐式原型上找,因为对象的隐式原型会从函数的显式原型那里继承属性。
上述代码打印出的结果为‘song’,因为实例对象自己没有name属性,在自己的隐式原型那(函数的显式原型)那找到了。
原型链
定义:在原型上加一个原型,再加一个原型...把原型连成链状,这种链状的访问顺序叫做原型链。
我们来看个例子
Ground.prototype.lastName = '漫威'
function Ground() {
}
var ground = new Ground()
Father.prototype = ground
function Father() {
this.name = '钢铁侠'
this.fortune = {
card: 'jia'
}
}
var father = new Father()
Son.prototype = father
function Son() {
this.hobit = 'reading'
}
var son = new Son()
console.log(son.name);
console.log(son.lastName);
上面代码输出结果为:‘钢铁侠’‘漫威’
可以看到函数Son,Father,Ground通过原型连接起来了,当想要访问son.name的值,会通过Son的显式原型访问Father构建对象的隐式原型找到了name的值为‘钢铁侠’;当想要访问son.lastName的值时,一样会通过Son的显式原型访问Father构建对象的隐式原型,还是没有;就又会通过Father的显式原型访问Ground构建对象的隐式原型,最终找到值输出‘漫威’。
扩展一下
我们来看张经典图
图片上展示了函数的显式原型与对象的隐式原型构成的原型链。函数的显式原型也是对象,也会有隐式原型__proto__,它会等于创造自己的函数的显式原型,一层一层最终会找到祖先。
总结
原型理解起来可能有点绕,但是它的作用是很大的,能很好地降低代码的耦合度,让代码更优雅。我们可以很好地利用原型链,避免重复写一些代码。