JavaScript原型与原型链

面向对象

在讲原型之前必须要将js与面向对象与之区分,之前我一直用面向对象的思想在往js上套,所以导致很多东西绞尽脑汁都没想明白,听人一句劝少走点弯路吧!😰😰

像java、c#这种典型的面向对象编程语言,类就是类,方法就是方法,子类继承父类非私有成员......对吧,姑且不说ES6、TS。就在ES5中,类是什么?函数是什么?构造函数又是什么?在js中,类就是函数,构造函数就是函数,函数就是对象,懵了吧😫,看🌰

//函数
 function star(){ }
 //构造函数
 function Star(uname,age){
     this.uname = uname;
     this.age = age;
 }
 console.log(Star instanceof Object) //true

在java中我们知道函数和构造函数都都是写在类中的,而且构造函数名跟类名得一致,这些性质在js上我们都看不到,离谱的是随便一个函数都可以是构造函数,只是说为了区分一下就将构造函数的首字母大写而已。那行吧,既然如此那么js怎么实现继承呢?首先别这么问吧,都说了不要拿着java那些玩意往js中套用,玩不明白的,这么问吧:怎样将公共的方法抽取出来(就如子类继承父类一样,父类的非私有成员都将被继承,子类可以复用这些父类的方法)?那就离不开原型和原型链了

在java中实例化对象怎么玩?得通过new关键字开辟内存空间吧,在js中方法很多:

     // 1.字面量
     var obj1 = {name: 'obj1'}
     var obj2 = new Object({name: 'obj2'})
     // 2.构造函数
     var O = function (name) { this.name = name; }
     var obj3 = new O('obj3')

__proto__

  • __proto__:是原型,叫做隐式原型,原型链就通过这玩意构成链。它存在实例对象上,每个实例对象都有一个属性叫做__proto__,指向原型对象

prototype

  • 原型对象:所有实例对象需要共享的属性和方法,都放在这个原型里面;不需要共享的属性和方法,就放构造函数里。原型对象的constructor属性指向构造函数

  • prototype:是原型,叫做显式原型,在每个函数上都有一个prototype属性,指向原型对象

//构造函数
 function Star(uname,age){
     this.uname = uname;
     this.age = age;
 }
 //原型 上设置 公共方法
 Star.prototype.sing = funciton(){
     consolo.log("我会唱歌")
 }
 let so = new Star('zhangsan',22)

上边例子中:

  • 实例对象通过new构造得到, so就是实例对象,Star就是构造函数。

  • 原型对象的 construor 指向的是构造函数。

每个函数都有一个 prototype 属性,prototype是函数才会有的属性。每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,就是所说的原型,每一个对象都会从原型"继承"属性。每一个对象最终关联到的对象是最底层的Object对象。如果还要杠,那Object关联自null。

原型链

那什么是原型链呢,刚才说了每个对象构造的时候都会通过__proto__属性与另一个对象相关联,最终关联自Object,那这不就形成了链吗。

简单理解就是原型组成的链,对象的__proto__它的是原型,而原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,就这样可以一直通过__proto__向上找,这就是原型链,当向上找找到Object的原型的时候,这条原型链就算到头了。

为什么要有链这个玩意,那是因为在js中没有面向对象中“继承”的这个概念,但是又要达到“继承”的这么个效果,减少代码的冗余,实现代码复用,所以就有了,所以只要是这个原型链上的内容,都可以被访问和使用到! 通过一个构造函数创建出来的多个实例,如果都要添加一个方法,给每个实例去添加并不是一个明智的选择。这时就该用上原型了。在实例的原型上添加一个方法,这个原型的所有实例便都有了这个方法。

function Star(uname,age){
     this.uname = uname;
     this.age = age;
 } 
 var so1 = new Star("zhangsan",12)
 var so2 = new Star("lisi",22)
 so1.__proto__.say=furnction(){
    console.log('hello world')
 }
 so1.say()  //hello world
 so2.say()  //hello world

按照JS引擎的分析方式,在访问一个实例的属性的时候,先在实例本身中找,如果没找到就去它的原型中找,还没找到就再往上找,直到找到。这就是原型链。

记住以下几个要点,基本就能够理解这一块的内容了,手写原型链自然就不在话下:

  1. 每个构造函数都有一个prototype属性,指向原型对象

  2. 每个对象都有一个__proto__属性,指向原型对象

  3. 每个原型对象都有一个个constructor属性,指向构造函数

好了记住这三点就能够手写原型链了,我先小试牛刀,献丑了

参考文章:原型与原型链详解 , 详谈JavaScript原型链

 

posted @ 2023-01-02 15:47  写点bug不过分吧  阅读(32)  评论(0编辑  收藏  举报