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) ```

相关推荐
光影少年5 小时前
angular生态及学习路线
前端·学习·angular.js
記億揺晃着的那天7 小时前
Vue + Element UI 表格自适应高度如何做?
javascript·vue.js·ui
无尽夏_7 小时前
HTML5(前端基础)
前端·html·html5
Jagger_7 小时前
敏捷开发流程-精简版
前端·后端
FIN66687 小时前
昂瑞微冲刺科创板:创新驱动,引领射频芯片国产化新征程
前端·安全·前端框架·信息与通信·芯片
GISer_Jing7 小时前
ByteDance——jy真题
前端·javascript·面试
睡美人的小仙女1277 小时前
浏览器为何屏蔽本地文件路径?
前端
真的想不出名儿7 小时前
Vue 中 props 传递数据的坑
前端·javascript·vue.js
FIN66687 小时前
昂瑞微:深耕射频“芯”赛道以硬核实力冲刺科创板大门
前端·人工智能·科技·前端框架·信息与通信·智能
阳光阴郁大boy7 小时前
星座运势网站技术解析:从零打造现代化Web应用
前端·javascript