new、原型和原型链浅析

new、原型和原型链

继承是编程里的一个常见思想。通过对父对象属性、方法的继承子对象可以不用编写相同的代码但能调用对应的属性、方法。

js通过原型来实现继承特性。

原型

在js中,在js中每一个对象都有一个自己的"父对象",这个"父对象"就叫做原型。

了解原型我们需要知道三个属性以及他们对应的含义

  • __ proto__ :对象的一个属性,指向这个对象的原型。
  • prototype :函数的独有属性,指向这个函数的原型。
  • constructor:对象的一个函数,指向这个对象的构造函数。

这里需要特别提到的有两点。

1、__ proto__在ES标准定义里的属性名应该是[[prototype]],具体实现是由浏览器代理自己实现。不同的浏览器可能在实现[[prototype]]上命名不同,功能是一致的。本文采用谷歌浏览器的实现命名方式__ proto__。

2、prototype是函数特有的属性,对象变量并没有prototype属性指向原型。但是由于函数也是一种对象,所以函数既有prototype,又有__ proto__,还有指向构造函数的constructor属性。

javascript 复制代码
let func = function(value){
    this.value = value
}

func.prototype.getValue = function() {
  return this.value;
}

let objA = new func(4);

这段代码是一个简单的通过new关键字将func函数作为构造函数来实例化一个对象objA

func()是一个构造函数,它有着特殊的属性prototype,在js中函数也是对象,所以它也有__ proto__constructorprototype__ proto__都指向原型func.prototype。 constructor指向func()的构造函数,这个在之后的原型链部分再讲。

func.prototype是一个原型对象,它也有__ proto__constructor。在js中一个构造函数的它的constructor指向构造函数

objA作为对象他有两个元素,__ proto__constructorconstructor指向构造函数func(), __ proto__指向原型。由于new关键字在实例化对象时是将构造函数的原型赋给实例化对象,所以__ proto__指向的是func.prototype。

func的prototype和objA的__ proto__都指向func.prototype,objAfunc.prototype的构造函数(constructor)都是func

new

通过new关键字调用一个函数时,将其视为一个构造函数,创建一个该构造函数的实例对象。这个对象拥有这个函数的共享属性、共享方法。具体实现在这里先不展示,需要知道的是: 在实例化这个对象的过程中,new将构造函数的prototype赋给了实例对象。

所以实例对象和构造函数实际上是共享一个原型。

原型链

对象有原型和构造函数,原型对象和构造函数也不例外。它们都有自己的原型和构造函数。 调用一个对象没有的方法时,该对象就会查找它的原型[[prototype]]查看是否有该方法,如果它的原型也没有该方法就会查找它原型的原型,直到查到Object.prototype。因为Object.prototype的原型是null。

这个通过[[prototype]]将各个原型穿起来链接就叫原型链。

如图所示从上到下分层来进行对这个原型链的解析。

第一层: ObjA是func()实例化对象,所以func()是ObjA的构造函数。在js内部,每个函数都是由Function()实例化而来所以Function()是fun()的构造函数。这里需要注意一点,其实ObjA自身是没有constructor属性的,在查询constructor属性时是遍历到自身的原型然后调用的原型的constructor。

所以实例对象的constructor == 实例对象的原型的constructor

Function()函数比较特殊,它自己就是自己的构造函数。

第二层:objA在实例化时func()将自身的原型赋给了它,所以objA和func()是同一原型。 由于ObjA是对象。所以只有__ proto__属性指向func.prototype。

每个构造函数在创建时,它的原型的constructor会自动指向它本身。 所以func.prototype.constructor == func。

同样Function.prototype.constructor指向Function()

第三层:由于fun.prototype是一个对象且它不是由其它构造函数构造得来,所以它的原型是Object.prototype,func.prototype.__ proto__ == Object.prototype。

Function.prototype作为一个Function()的原型对象,自然它的原型也指向Object.prototype,Function.prototype.__ proto__ == Object.prototype。

Object()是Object的构造函数,所以Object().prototype.constructor == Object()

第四层:Object()作为最上层的对象,所有的对象都是从Object.prototype直接或间接继承而来。所以Object()再往上没有原型。 Object.prototype == null

补充一下:

\[prototype\]\]可以通过Object.setPrototypeOf修改构造函数的原型,但是不建议这么做,因为构造函数在修改原型时不会一同修改 ```javascript let func = function(value){ this.value = value } func.prototype.getValue = function() { return this.value; } let objA = new func(4); console.log(objA.value) let o = function(value){ this.value = value + 1 } Object.setPrototypeOf(func.prototype, o.prototype) let objB = new func(2); console.log(objB.value) ```

相关推荐
spmcor几秒前
Vue命名冲突:当data和computed相爱相杀...
前端·面试
拉不动的猪1 分钟前
单点登录中权限同步的解决方案及验证策略
前端·javascript·面试
znhy@1234 分钟前
十三、JS进阶(二)
开发语言·前端·javascript
JarvanMo20 分钟前
Flutter:使用图像作为屏幕背景
前端
Mintopia22 分钟前
💰 金融Web应用中的AIGC风险控制技术与合规适配
前端·javascript·aigc
Mintopia26 分钟前
🚀 Next.js 压力测试与性能调优实战
前端·javascript·全栈
江城开朗的豌豆26 分钟前
TypeScript 类型系统漫游指南:从入门到爱上类型安全
前端·javascript
江城开朗的豌豆31 分钟前
从 JavaScript 到 TypeScript:我为什么选择了类型守护
前端·javascript
杨超越luckly1 小时前
HTML应用指南:利用POST请求获取全国爱回收门店位置信息
大数据·前端·python·信息可视化·html
冷崖1 小时前
QML-Model-View
javascript·c++