JS 原型链(对象、构造函数、实例 三者的关系)及 prototype 作用

 想理解更深可参考: 深入javascript之原型和原型链 https://blog.csdn.net/yucihent/article/details/79424506

这篇文章有空需要更加深去看一下详谈JavaScript原型链 https://www.cnblogs.com/chengzp/p/prototype.html

重点:

  • 原型链最重要的作用就是继承,实例来继承上一级的属性或方法。此外,如果有多个实例,而多个实例存在共同方法,或共同属性,我们不想每一个实例都创建一份这些属性或方法,就可以将这些属性存在原型对象上,实例一样可以使用这些属性或方法;
  • 类似于作用域链,实例在调用方法时,如果在本身没有找到,就会在原型对象上查找,如果也没有找到,就会再向上一级原型对象查找,一直找到Object.prototype ;如果中间找到会停止查找返回该方法。如果一直没找到会返回未定义;

要理解原型链就要明白原型对象、构造函数、实例,三者之间的关系。 
我们先来梳理三者的关系: 
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实力也有一个指向原型对象的内部指针。 
当这个原型对象是另一个类型的实例,那么这个原型对象就有一个内部指针指向另一个原型,以此类推就构成了一条原型链。原型链的根就是Object.prototype。 
文字描述往往没有图像描述来的直观,那么我们用一个三者之间的关系图来直观的了解。

如上图所展示的,原型对象指向构造函数的指针是 constructor ,构造函数的 prototype 指向原型对象,构造函数通过 new 操作符来创建一个实例 , 实例又可以通过内部指针 proto 指向原型对象。 
proto 连接的这一条原型对象就构成了原型链。

如上面列举的创建对象方式的第二种方式,M 就是一个构造函数,那么 M 就应该有一个 原型对象,可以通过 prototype 找到!而 M 的原型对象存在 constructor,按照上图所示, M 的 原型对象的 constructor 指向的就是 M 本身;实践看结果: 
 
上图就可以明了的证明构造函数和原型对象之间的关系; 
那么我们再来看实例和原型对象的关系。依照上面的关系图,实例的内部指针 proto 指向原型对象,构造函数 M 的原型也指向同一个原型对象,究竟指向的是不是同一个原型对象呢?我们再来看: 
 
这样两个例子就很明白的说明了实例、构造函数、原型对象三者之间的关系。 
那么明白了三者之间的关系我们就来说一下原型链,从一个实例对象向上找有一个构造实例的原型对象,这个原型对象又有构造它的上一级原型对象,如此一级一级的关系链,就构成了原型链。原型链的最顶端就是Object.prototype ;

原型链最重要的作用就是继承,实例来继承上一级的属性或方法。此外,如果有多个实例,而多个实例存在共同方法,或共同属性,我们不想每一个实例都创建一份这些属性或方法,就可以将这些属性存在原型对象上,实例一样可以使用这些属性或方法; 
 
类似于作用域链,实例在调用方法时,如果在本身没有找到,就会在原型对象上查找,如果也没有找到,就会再向上一级原型对象查找,一直找到Object.prototype ;如果中间找到会停止查找返回该方法。如果一直没找到会返回未定义;


 class person{
    constructor(age,sex){
      this.age=age
      this.sex=sex
      this.hobby="running"
      this.name="ling"
    }
    say(word){
      alert(word)
    }
  }

var ling=new person()//用new 方法创建一个 名为 ling 的 实例

  class baby extends person{  //baby 继承父类 person 的属性和方法
    constructor(){
      super("5months","female") //这里和上面person 类在 constructor 传入的两个参数
      this.name="xinxin"
      this.food="milk"         //constructor 中,可以添加新属性,或者其他代码
    }
  }

  let xinxin =new baby()

根据上文的关系分析,结合例子,

原型对象  对应  person的实例 (这里的person的实例,指的是 person 类中,用constructor创建的实例,而不是特指某个已经创建出来的具名实例,比如用 new 方法创建出来的对象 ling)

构造函数  对应  baby

实例         对应  xinxin

console.log(xinxin.__proto__===baby.prototype)

检测第一级原型对象 是否指向同一个,执行结果为true 

 

console.log(xinxin.__proto__.__proto__===person.prototype)

上去第二级原型对象, 执行结果也为true 


 prototype 和 _proto_

只有函数有prototype,对象是没有的。

但是函数也是有__proto__的,因为函数也是对象。函数的__proto__指向的是Function.prototype。

也就是说普通函数是Function这个构造函数的一个实例。

 

instanceof原理

instanceof是判断实例对象的__proto__和生成该实例的构造函数的prototype是不是引用的同一个地址。

是返回true,否返回false。

注意:实例的instanceof在比较的时候,与原型链上想上找的的构造函数相比都是true。

 继续上面的代码

那怎么判断实例是由哪个构造函数生成的呢?这时候就要用到constructor了。

实例的原型的构造函数, obj.__proto__.constructor

 


原型对象和实例之间有什么作用呢?

通过一个构造函数创建出来的多个实例,如果都要添加一个方法,给每个实例去添加并不是一个明智的选择。这时就该用上原型了。

在实例的原型上添加一个方法,这个原型的所有实例便都有了这个方法。

var M = function (name) { this.name = name; }
var o3 = new M('o3')
var o5 = new M()
o3.__proto__.say=furnction(){
   console.log('hello world')
}

o3.say()
o5.say()

打印结果

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值