搞不懂的原型和原型链

什么是原型呢

我们先来看定义:原型是函数function对象自带的一个属性,它定义了构造函数制造出来的对象的公共祖先。通过构造函数产生的对象,可以继承到原型属性和方法。 原型本身也是对象。

不是很理解,没关系,我们边看代码边解释:

Person.prototype.name = '小明'
Person.prototype.say = function(){
    console.log('你好')
}

function Person(){//构造函数

}

var person = new Person()//实例化

console.log(person.name)//小明
console.log(person.say())//你好
复制代码

上面代码我们写了个构造函数Person,往它的原型上放一个属性name,和一个方法say()。通过它的实例化对象可以访问到原型上的属性。

这个好理解,那么请问实例化对象person是否含有name属性和say()方法呢?接下来我们输出一下就知道

console.log(person) // Person {} 
console.log(person.name) //小明
复制代码

结果实例化对象person居然是个空对象,但是却可以访问到name属性!!!是否出乎你的意料

那么我如果往构造函数里面增加属性name,结果又是如何呢

function Person(){
this.name = '小君'
}
console.log(person) //Person{name:'小君'}
console.log(person.name) //小君
}
复制代码

所以,看了上面的代码再结合定义不难想到,所谓原型就是一个函数自带的属性,它定义了所以函数实例化对象的公共祖先。实例化对象是个独立的个体,只是和原型建立了一层连接关系。如果实例化对象自己没有该属性或方法,就会跑到祖先哪里去找。自己是无法拥有该属性的,只能继承祖先的属性和方法。如果自己重写了继承过来的属性或方法,那自己拥有该属性或方法。

懂了这个,那自然而然原型链也好理解了。

什么是原型链呢

我们还是先看定义:在原型上加一个原型,再加上一个原型...把原型连成链,访问顺序也是按照链的顺序执行,叫做原型链

还是有点抽象,我们还是放上代码来解释

Grand.prototype.lastname = '李'
 function Grand(){
 }
var grand = new Grand()
//----------------------------------------

 function Father(){
this.fortune = {
    card1:'visa'
}
this.num = 100
 }
 var father = new Father()

//------------------------------------------
 function Son(){
this.hobbit = '读书'
 }
 var son = new Son()
复制代码

上面代码有点长但是不然理解,结合生活来讲,定义了三个构造函数,分别是Grand(爷爷)、Father(爸爸)、Son(儿子) 爷爷姓'李',爸爸有张银行卡(card1),总额为100。 请问怎么让爸爸和儿子也和爷爷一个姓(按理来讲,直接继承就行,不需要重新定义一个),儿子怎么使用爸爸的银行卡呢?

解决上面的问题,就需要用到上面说的原型链,把这个三个函数连在一起。我们修改一下上面的代码,如下:

Grand.prototype.lastname = '李'
 function Grand(){
 this.name = '小虎'
 }
var grand = new Grand()
//----------------------------------------

Father.prototype = grand//让爸爸的原型指向爷爷
 function Father(){
 this.name = '小龙'
this.fortune = {
    card1:'visa'
}
this.num = 100
 }
 var father = new Father()

//------------------------------------------
Son.prototype = father //让儿子的原型指向爸爸
 function Son(){
this.hobbit = '读书'

 }
 var son = new Son()
 
  console.log(son.hobbit);//读书
  console.log(son.fortune);//{card1: 'visa'}
  console.log(son.lastname)//李
  
  console.log(son.name)//小龙
复制代码

把三个人物链接起来 爷爷->爸爸->儿子 就解决了上面的问题

但是定义还说了一点,就是访问顺序也是按照链的顺序执行,所以上面输出儿子的名字是爸爸的名字而不是爷爷的名字,因为儿子的上一个原型是爸爸哦。这下明白了吧。

接下来我们来聊聊原型的作用

function Car (color,owner){
     this.weight = 4900
    this.brand = 'BMW'
    this.color = color
    this.owner = owner
}

var car1 =new Car('pink','laisf')
var car2 =new Car('green','xqm')

复制代码

上面代码定义了一辆车(Car),拥有属性:体重(weigh),品牌(brand),颜色(color),名字(owner),然后两个实例化对象car1,car2。

其实这个两辆车只是颜色和名字不一样,其他像体重和品牌其实在生产出来都是一样的。也就是说,没有必要每次实例化对象时,都重新执行 this.weight = 4900 this.brand = 'BMW'这两行代码,有点多余,这是每一辆车共有的东西,是不需要每次都重复生产出来,只需要拿个模板就行。而那些真正要改变的,就是带点个性的东西(如颜色,名字),才是需要去手动去改变的。 所以,我们来简化一下代码吧:

Car.prototype ={
    //往原型上放两个属性
    weight :4900,
    brand : 'BMW'
}
function Car (color,owner){
    this.color = color
    this.owner = owner
}
var car1 =new Car('pink','laisf')
var car2 =new Car('green','xqm')
复制代码

这样就达到了可以提取共有属性的目的,代码也不会那么的冗余,高级程序员就会这样写哦。你学会了吗?

おすすめ

転載: juejin.im/post/7032571565296812040
おすすめ