小白零基础准备面试:js中的原型和原型链

440 阅读5分钟

前言:原型的理解在于你对于JavaScript中的对象和继承关系的认知,如果你并不是很清楚,那身为小白的你可以看看我写的原型,肯定会让你对原型有一个很好的理解


一、什么是JavaScript中的原型?

定义:是函数function对象的一个属性,它定义了构造函数制造的对象的公共祖先。通过构造函数产生对象,该对象可以继承原型的属性和方法,原型也是对象。
//Person.prototype --原型  数据结构: {}
Person.prototype.say = function(){
    console.log('哈哈哈哈');
}
    function Person(){
        this.name = '红红'
    } 
let p = new Person()  // 得到一个实例对象

p.say()
console.log(p)

vscode:js执行结果

1.jpg

浏览器:执行结果

2.jpg 以上代码发现:p的显示对象中并没有发现有say()这个方法,但是在执行过程中依然可以访问,说明了p隐式继承了say()这个方法。通过浏览器的执行结果来看,我们可以发现Person下面有一个[[Prototype]]属性、且[[Prototype]]属性下面又有一个say()方法。由此我们可以说明,Person隐式继承了这个say()方法


二、原型的两种类型

函数原型:显示原型---prototype 函数天生具有的原型属性
Car.prototype ={
    carName :'bgw',
    height :1400,
    lang :3900
}
//函数原型 显示原型

function Car(owner,color){
    this.owner = owner
    this.color = color
}
var a = new Car('snake','black')
console.log(a)

对象原型:隐式原型---[[Prototype]] __proto__对象天生具有的原型属性
 <script>
        Person.prototype.name = 'John';
        function Person(){
            this.a = 1
        }
        var person = new Person
        console.log(person)//隐式原型  对象原型
    </script>

三、原型特性

1. 利用原型的特点和概念,可以提取公有属性,不需要在每次创建对象时都执行,降低了代码的耦合度(代码的关联性)。

以下以一个创建车库的例子:
有一个宝马工厂生产了一车子,但是车子除了名字和颜色需要用户自己diy外,无需其他改变。
常规手法:代码一

function Car(owner,color){
    this.carName = 'bgw'
    this.height =1400
    this.lang = 3900
    this.owner = owner
    this.color = color
}
var a = new Car('snake','black')
console.log(a)


用了原型特性的手法:代码二

Car.prototype ={
    carName :'bgw',
    height :1400,
    lang :3900
}
function Car(owner,color){
    this.owner = owner
    this.color = color
}
var a = new Car('snake','black')
console.log(a)

对比两串代码的执行结果,我们发现,代码一中,每一条代码都重新执行了一遍,造成的结果是过于复杂,而代码二中提取出了公有属性,正好符合了我们的预期结果只打印出了,我们自定义的效果。因此,合理的利用原型,可以降低代码的耦合度。

2. 实例对象无法对原型做 增删改查

我们通一过一个修改的例子来展示,思考下现在的打印结果是什么

function Person(name){
    this.name = name;
}
Person.prototype.lastName =  'yang'
var p = new Person('hong');

p.lastName = 'jiang'
console.log(p.lastName)

然后我们在修改一下代码,思考一下现在的打印结果是什么

function Person(name){
    this.name = name;
}
Person.prototype.lastName =  'yang'
var p = new Person('hong');
var p2 = new Person('hong');

p.lastName = 'jiang'
console.log(p2.lastName)

下面来展示结果:

结果一

3.jpg
结果二

4.jpg

通过结果一和结果二对比,我们发现Person里面的隐式对象并没有发生改变。结果一里面只是又重新添加了一个name = jiang的属性,所以打印结果才有了,但是并没改变其中的原型对象,因此我们可以举一反三得出一个结论就是:实例对象无法对原型做 增删改查。(有不相信的码友可以自己去尝试尝试)

3 .实例对象的隐式原型 __ proto__ === 构造函数的显示原型(prototype)
 <script>
        Person.prototype.name = 'John';
        function Person(){
            this.a = 1
        }
        var person = new Person
        console.log(person)//隐式原型  对象原型
    </script>

5.jpg 我们打印出来发现对象身上也具有一个原型,函数自身身上也有一个原型,两者的值是相等的,因此,我们可以知道,为什么可以访问到原型身上的显示原型,正是因为,其对象身上的隐式原型等于函数身上的显示原型从而可以进行访问。


四、原型链

在原型上加一个原型,再加一个原型...把原型连成链状,这种原型的链状的访问顺序叫做原型链,直到找到null为止

我们来思考一个问题,实例对象的隐式原型等于什么?

很简单:等于构造函数的显示原型。

然后我们再思考,构造函数的显示原型是一个对象,那么构造函数的显示原型有没有隐式原型。

很显然:是对象就有隐式原型

    <script>
        function Init(){
        }
        var init = new Init();

        console.log(init);//{__proto__:xxx}
    </script>

6.jpg 即:[[Prototype]]:Object 也是一个对象

7.jpg 然后我们又可以发现:对象的隐式原型又等于构造函数的显示原型:即又是一个对象,那么对象又应该有一个原型。
我们发现这样子似乎好像可以无限套娃。但实际上,我们最终的结果只能到Object这一层。因为Object是最终的创建者,就到了底部了。即到了最终-- _ proto _:null 结束

8.jpg 了解了以上内容我们可以开始看看这个列子

    <script>
        Ground.prototype.lastName = '周'
        function Ground(){

        }
        var ground = new Ground()
        Father.prototype = ground
        function Father(){
            this.name = '子成'
            this.fortune ={card:'visa'}
        }
        var father = new Father()
        Son.prototype = father

        function Son(){
            this.hobit = 'readings'
        }
        var son = new Son()
        console.log(son.lastName)
    </script>

9.jpg 我们发从Son开始,往上加了一个Father的原型,然后Father的身上又加了一个Ground的原型,然后Ground自身身上又加了一个显示原型。因此当我们从儿子身上访问lastName属性时,我们会一路往上找。并且这种关系呈现一种链型的关系。因此我们称这种原型的链型关系,为原型链


五、总结

JavaScript 中的对象,都有一个内置属性Prototype,指向这个对象的原型对象。当查找一个属性或方法时,如果在当前对象中找不到,会继续在当前对象的原型对象中查找;如果原型对象中依然没有找到,会继续在原型对象的原型中查找(原型也是对象,也有它自己的原型);直到找到为止,或者查找到最顶层的原型对象中也没有找到,就结束查找,返回 undefined。这个查找过程是一个链式的查找,每个对象都有一个到它自身原型对象的链接,这些链接组建的整个链条就是原型链。拥有相同原型的多个对象,他们的共同特征正是通过这种查找模式体现出来的。

读到这里如果对你有点作用的话,可以给一个小小的点赞吗,你的点赞是我持续写下去的动力。 然后有什么写的不好地方也欢迎指出不住。