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

相关推荐
Ticnix2 小时前
函数封装实现Echarts多表渲染/叠加渲染
前端·echarts
阿星做前端2 小时前
coze源码解读: space develop 页面
前端·javascript
叫我小窝吧2 小时前
Promise 的使用
前端·javascript
NBtab2 小时前
Vite + Vue3项目版本更新检查与页面自动刷新方案
前端
天天扭码2 小时前
来全面地review一下Flex布局(面试可用)
前端·css·面试
用户458203153172 小时前
CSS特异性:如何精准控制样式而不失控?
前端·css
libraG3 小时前
Jenkins打包问题
前端·npm·jenkins
前端康师傅3 小时前
JavaScript 作用域
前端·javascript
前端缘梦3 小时前
Vue Keep-Alive 组件详解:优化性能与保留组件状态的终极指南
前端·vue.js·面试