【js进阶】-原型/原型链

一、构造函数创建对象

我们先使用构造函数创建一个对象,先来认识下构造函数

function Person() {
}
var person1 = new Person();
person1.name = '张三';
console.log(person1.name) // 张三

在这个例子中,Person 就是一个构造函数,我们使用 new 创建了一个实例对象 person1

prototype

每个函数都有一个 prototype 属性,它指向的是一个对象,既然它是一个对象,我们就手动给上面例子中的Person.prototype对象增加一个color属性:

function Person() {   //构造函数Person
}

Person.prototype.color = 'white';   //给Person.prototype对象增加一个color属性
const person1 = new Person();   // 创建第一个实例对象person1
const person2 = new Person();  // 创建第二个实例对象person2
console.log(person1.color) // white
console.log(person2.color) // white

其实,函数的 prototype 属性指向的这个对象,正是调用该构造函数而创建的实例对象的原型(原型对象),也就是这个例子中的 person1 和 person2 的原型(原型对象)

那什么是原型呢?你可以这样理解:每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中"继承"属性,就是因为会"继承"原型对象中的属性,所以上述例子中创建的两个实例对象person1和person2都默认拥有了color属性,这个color属性就来源于Person.prototype这个原型对象

让我们用一张图表示构造函数和实例原型之间的关系:
在这里插入图片描述
这时候,有部分思考的同学就会问了,那你刚才举的例子是通过构造函数创建的实例对象是这样的,那如果直接通过字面量的形式创建的对象也会是这样的吗?

好,我们就来看下:
在这里插入图片描述
上述代码可以看出通过字面量形式直接创建的对象obj,它也是"继承"其原型对象上的属性(toString),可能有些同学对于_proto_属性不太清楚,没关系,我们马上就讲,这里你只需要知道对象中的_proto_属性指向其原型对象就可以了,所以这也印证了之前说的那句话:每一个对象都会从原型中"继承"属性

_ proto _

这是每一个JavaScript对象(除了 null )都具有的一个属性,叫__proto__,这个属性会指向该对象的原型。

为了再次验证该说法,我们还是以第一个例子为例:
在这里插入图片描述
于是我们更新下三者(构造函数-原型对象-实例对象)的关系图:
在这里插入图片描述
既然实例对象和构造函数都可以指向原型,那么原型是否有类似属性指向构造函数或者实例呢?

constructor

每个原型对象都有一个 constructor 属性指向关联的构造函数。

function Person() {

}
console.log(Person === Person.prototype.constructor); // true

所以再更新下关系图:
在这里插入图片描述

实例属性查询机制

读取实例的属性时,如果找不到,就会查找与该实例对象关联的原型中的属性,如果还查不到,就去找原型的原型,直到最顶层为止(Object.prototype)。

function Person() {    // 构造函数Person
}

Person.prototype.color = 'white';
const  person1 = new Person();   //创建一个实例对象

person1.color = 'black';   // 给该实例对象赋值一个color属性,值为black
console.log(person1.color) // black

delete person1.color;   //删除实例对象上的color属性
console.log(person1.color) // white   

在这个例子中,我们给实例对象 person1 添加了 color 属性,当我们打印 person1.color 的时候,结果自然为 black。

但是当我们删除了 person1 的 color 属性时,读取 person1.color,此时person1 对象中找不到 color 属性时就会从 person1 的原型也就是 person1.__ proto __ ,也就是 person1.prototype中查找,幸运的是我们找到了 color 属性,结果为 white。

原型的原型是谁(最终源头是谁?)

我们知道原型对象其实也就是一个对象,那既然是对象它就是可以通过new Object()的方式来创建,所以原型对象其实就是Object的实例对象,所以上述例子中Person.prototype原型对象的原型就是Object.prototype

function Person() {    // 构造函数Person
}
Person.prototype.__proto__ === Object.prototype    // true

在这里插入图片描述

原型链

那 Object.prototype 的原型呢?

是null,我们可以打印看看:

console.log(Object.prototype.__proto__ === null) // true

所以 Object.prototype._ proto _ 的值为 null 跟 Object.prototype 没有原型,其实表达了一个意思。所以查找属性的时候查到 Object.prototype 就可以停止查找了。

最后一张关系图也可以更新为:

在这里插入图片描述
其实上图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线。

特殊注意点

1、我们看个例子:

function Person (){}
const person3 = new Person();
person3.constructor === Person   

上面例子中可以看出创建的实例对象中也有constrctor属性,它也是指向创建它的构造函数,看到这有些同学有点蒙了,刚才不是说原型对象中有一个constrctor属性指向构造函数吗?现在怎么实例对象中也有该属性,怎么这么乱呢?

其实这里的constructor属性就是"继承"原型对象中的constructor属性,实例对象本身没有该属性,它自身没有就会去它的原型对象中找,这样解释是不是就立马通顺了…

person.constructor === Person.prototype.constructor   // true

2、全篇一直对于"继承"这个词语用引号括起来了,这是因为这种说法并不恰当,因为继承意味着复制操作,然而 JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ronychen’s blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值