js里面的原型

194 阅读6分钟

原型

什么是原型?

原型是函数上的一个属性,它定义了构造函数制造构造函数的公共祖先

原型的作用:

1属性和方法的共享(函数的原型prototype)

下面,我们来看一段代码


function Car( color, owner)
            {
                this.name='su7'
                this.lang=5000
                this.height=1400
                this.color =color
                this.owner='宇哥'
            }
            
            let Car1= new Car('black','鹏哥')
            let Car2 = new Car('white','牛哥')

在这里,我定义了一个Car方法,当我们想要创建一个实例对象的时候,需要new一个实例对象,那么,如果我们想要创建多个实例对象,100个,1000个,是不是要写100行,1000行这种代码,这样显的是不是很不优雅?

那么我们有没有别的方法呢?

     
        Car.prototype.name='su7'
        Car.prototype.lang = 5000
        Car.prototype.height = 1400
            function  Car( color, owner)
            {
                this.color =color
                this.owner=owner
            }
            let Car1= new Car('black','鹏哥')
            let Car2 = new Car('white','牛哥')
             console.log(Car1.name)
             console.log(Car2.lang)

在这里,我们把公共的属性 name='su7'lang = 5000height = 1400定义在了外面, 我们来看打印结果

微信截图_20240710192400.png

Car1和Car2没有name,lang ,height这几个属性,那么是不是这两个实例对象不包含这几个属性呢?

接下来,我们来访问一下实例对象里的这几个属性


        Car.prototype.name='su7'
        Car.prototype.lang = 5000
        Car.prototype.height = 1400
            function  Car( color, owner)
            {
                this.color =color
                this.owner=owner
            }
            let Car1= new Car('black','鹏哥')
            let Car2 = new Car('white','牛哥')
             console.log(Car1.name)
             console.log(Car2.lang)

在这里,我们访问Car1的 name属性Car2的 lang属性 这个时候,我们在控制台发现有打印结果

微信截图_20240710191740.png

是不是很奇怪? 上面打印了Car1对象,发现没有name这个属性,但是访问的时候却能访问到

解释:在这这里,我们把name , lang ,height,叫做Car1 ,Car2 隐士具有的属性,也叫继承。于是我们得到一句话: 构造函数new 出来的对象会隐式继承到 构造函数原型上的属性

实例对象可修改显示继承到到的属性,但是无法增加删除修改隐士继承的属性(原型上的),那是可以查询隐式继承的属性

对象的原型 p.___proto ___

那么,两者的之间有什么关系呢?


    function Person(){

     }
     
     let p =new Person()
     console.log(Person.prototype)
     
     console.log(p.__proto__)

在这里,我们打印函数的原型和由这个构造函数创建的实例对象的原型

微信截图_20240710195422.png

我们发现,两者是一样的,这个时候,我们得出一个结论:

对象的隐式原型==创建它的构造函数的显示原型


   Person.prototype.say=function(){
        console.log('hello')
    }

     function Person(){

        this.name='Tom'

     }
     let p =new Person()
     console.log(p.say())

   打印结果:hello

我们都知道,p是构造函数Person创建的一个实例对象,当我们访问p的say()方法时,会打印hello

那么为什么会这样呢?我们来打印一下实例对象p

我们发现,实例对象p里面有一个显示属性name,还有一个隐式属性say

微信截图_20240710201225.png

解释一下,这里的constructor指的是由谁创建这个对象,比如这个实例对象p是由Peron这个构造函数创建的

这里,我们得出一个结论

对象会隐式继承创建它的构造函数的属性,js引擎在查找属性时,会先查找显示具有的属性,找不到,再查找隐式具有的属性

p.___proto ___ == Person.prototype(对象的隐式原型==构造函数的显示原型)

构造函数的显示原型Person.prototype是一个对象,在js当中,只要是一个对象,就有隐式原型

xxx的隐式原型是创建xxx的构造函数的显示原型,Person是由Object创建的,所以有

Person.prototype. p.___proto ___ ==Object.prototype

接下来,我们来看一段代码,来对原型有一个更深的理解


      grandFather.prototype.say = function () {
                console.log('haha')
            }

            function grandFather() {
                this.age = 60
                this.like = 'drink'
            }

            Father.prototype = new grandFather()
            function Father() {
                this.age = 40
                this.fortune = {
                    card: 'visa'
                }
            }
            Son.prototype = new Father()
            function Son() {
                this.age = 18
            }
           let p =new Son()

            console.log(p.say())
        

当v8执行这段代码时,

1.因为son的显示属性没有say()方法,所以会找实例对象p的隐式原型p.___proto ___

2实例对象son的隐式原型p.___proto ___ 等于Son()构造函数的显示原型Son.prototype

p.___proto ___ == Son.prototype

3.Son()构造函数的显示原型Son.prototype等于一个由构造函数Father()创建的实例对象,记为father

4.我们发现father 里面没有say()方法,

5.所以会找 father的隐式原型 father.___proto ___ ==构造函数的显示原型

father.___proto ___==Father.prototype

Father.prototype ==new grandFather

6.我们发现它等于一个由 grandFather()创建的一个实例对象,这个对象里面也没有say()方法,,由new Father创建的对象记为grandfather

7.所以会找 grandfather的隐式原型 grandfather.___proto ___ ==构造函数的显示原型

grandfather.___proto ___==grandFather.prototype ==say()

所以,最终打印haha

我们把这种关系称之为原型链

什么是原型链?

原型链(Prototype Chain)是用于实现继承属性查找的一种机制。当你访问一个对象的某个属性或方法时,如果该对象自身没有这个属性或方法,JavaScript引擎会沿着原型链向上查找,直到找到这个属性或方法或者到达原型链的终点。

  1. 原型链的形成:

    • 当一个对象被创建时,其__proto__属性被初始化为其构造函数的prototype
    • 构造函数的prototype对象也有自己的__proto__属性,这通常是Object.prototype
    • Object.prototype__proto__属性是null,这标志着原型链的结束。
  2. 属性查找过程:

    • 当尝试访问一个对象的属性时,JavaScript引擎首先检查该对象本身是否具有这个属性。
    • 如果没有找到,引擎会沿着__proto__链向上查找。
    • 查找过程会一直持续,直到找到该属性或到达原型链的末端(null)。

总结一下

原型与原型链总结

  1. 原型(Prototype) :

    • 是函数的一个属性,用于定义对象的公共祖先。
    • 通过构造函数创建的对象会继承其构造函数的原型上的属性和方法。
  2. 共享属性和方法:

    • 公共属性和方法可以定义在构造函数的原型上,使所有实例共享这些属性和方法。
    • 例如,将 Car.prototype.name 定义在原型上,所有 Car 的实例都能访问 name 属性。
  3. 对象的隐式原型:

    • 每个对象都有一个隐式原型属性 __proto__,指向其构造函数的原型对象。
    • 实例对象的隐式原型 p.__proto__ 等于其构造函数的显示原型 Person.prototype
  4. 原型链(Prototype Chain) :

    • 当访问对象属性时,JavaScript 引擎会先查找对象本身的属性,找不到则沿着原型链向上查找,直到 Object.prototypenull
    • 原型链用于实现继承和属性查找,是多个对象通过原型连接形成的链条。

制作不易,感谢支持