原型与原型链

原型与原型链

构造函数、原型、原型链关系图:

原型原型链关系图

原型和原型链

js中的对象(js中一切皆对象)我们可以对它进行增删改查(CRUD)的操作。

如果新声明一个对象: let obj = {} ,会发现这个对象自带了一些属性和方法,这些属性和方法实际上是继承的。

比如: valueOf() , toString() , constructor

obj继承的

这些继承的属性和方法都在 obj.__proto__ 对象中, obj.__proto__ 对象继承自 Object.prototype
想要调用继承的属性和方法只需要 obj.property_name ,js提供了 __proto__ 访问器来访问继承的属性和方法。

obj.__proto__ 中也有 __proto__ ,它的值是 null
其实 obj.__proto__ 就是 Object ,而 obj.__proto__.__proto__ 就是 null ,也就是说 Object 的原型为 null

我们在调用 obj.valueOf() 的时候,js会先找obj自己本身有没有 valueOf() ,如果有就用自己的,如果没有就会在 obj.__proto__ 对象中找 valueOf() ,如果也没有就再在 obj.__proto__.__proto__ 中找,直到找到或者找不到为止,而这个找的路径就称之为原型链

实际上如果再定义一个对象,其 __proto__ 对象也是和 obj.__proto__ 一样的。如果修改了其中一个对象的 __proto__ ,另一个对象的 __proto__ 也是被修改了,因为他们都继承自 Object.prototype

如果想要异化两个对象的 valueOf() 的行为,可以单独给两个对象添加 valueOf() 方法。

比如:

1
2
3
4
5
6
7
obj.valueOf = function() {
// ...
}

obj2.valueOf = function() {
// ...
}

js对象模型

对于上图的总结如下:

  • 所有的对象都有_proto_属性,该属性对应该对象的原型
  • 所有的函数对象都有prototype属性,该属性的值会被赋值给该函数创建的对象的_proto_属性
  • 所有的原型对象都有constructor属性,该属性对应创建所有指向该原型的实例的构造函数
  • 函数对象和原型对象通过prototypeconstructor属性进行相互关联

只要记住一点,函数有原型对象( prototype ),其他的对象就只有原型( _proto_ )。所以这两个通常被称为显式原型和隐式原型。

prototype和__proto__

  • 对于所有的对象,都有_proto_属性,这个属性对应该对象的原型。
  • 对于函数对象,除了_proto_属性之外,还有prototype属性,当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的_proto_属性)

实例:

1
2
3
4
5
6
7
8
9
10
11
12
// 构造函数
function Person(name) {
this.name = name;
}

// 给Person原型链上添加age属性
Person.prototype.age = 22;

// 实例化Person
let p = new Person();
// 结果:对象p继承了Person.prototype对象,通过p.[属性/方法]来调用Person.prototype对象中的属性和方法
console.log(p.age); // 22

ref

  1. https://zhuanlan.zhihu.com/p/23090041
  2. https://zhuanlan.zhihu.com/p/58605553
  3. https://zhuanlan.zhihu.com/p/294808520
  4. https://www.cnblogs.com/loveyaxin/p/11151586.html
  5. https://zhuanlan.zhihu.com/p/356980105

评论