彻底搞懂JavaScript中的原型(__proto__)、原型对象(prototype)及原型链
2024-03-26 08:20:56一. 原型(__proto__)
任何对象(除了null以外)上都会有一个内部属性__proto__。这个属性就是对象的原型,你可以在控制台中通过obj.__proto__打印(obj是定义的一个对象)。
但是需要注意的是,这个属性是一个内部属性,在平时开发代码中是不能直接使用这个属性,你可以通过getPrototypeOf(获取)、setPrototypeOf(设置)等。
那__proto__指向什么呢?你可以理解为构造该对象的构造函数的prototype。比如我们通过 new 一个构造函数,创建一个对象:
function A() {}
const a = new A();
那它(a)的__proto__指向的就是构造它的构造函数(A)的prototype,即:
a.__proto__ === A.prototype
二. 原型对象(prototype)
原型对象是针对函数的,在函数中,我们可以定义一些原型方法和原型属性,之后通过函数new的实例对象上都可以访问这些原型方法和属性,减少了内存占用。
function Person() {}
Person.prototype.getName = function() {
return “我是原型方法”;
}
const person1 = new Person();
const person2 = new Person();
person1.getName(); // 我是原型方法
person2.getName(); // 我是原型方法
需要注意的是:函数也是一种对象,因此函数不仅有prototype,也有__proto__属性。
上面定义的Person构造函数的__proto__:
Person.__proto__ === Function.prototype
三. 原型链
原型链是一种查找规则。
当查找一个对象上的属性或者方法时,首先从自身属性开始查找,如果没有,则去该对象的原型上查找(__proto__),如果没有,再去对象的原型的原型上去查找,直至null(Object.prototype.__proto__ === null)结束,这种链式查找,被称为原型链。
下面我会详细介绍该如何毫无压力的写成任何对象的原型链。
比如我们创建一个构造函数,之后new一个对象,我们以这个对象为例:
function A() {}
const a = new A();
a对象的原型链:
构造a对象的构造函数是A,那么a.__proto__:
a.__proto__ === A.prototype
A.prototype.__proto__呢?可能会有人回答是Function.prototype,A的构造函数不是Function嘛,那可以明确告诉你,A.prototype.__proto__不是指向Function.prototype,而是指向Object.prototype,为啥呢,因为A.prototype,而不是A,A的构造函数是Function,但是A.prototype可不是,它是一个对象,那它的构造函数是Object,所以:
A.prototype.__proto__=== Object.prototype
Object.prototype.__proto__呢?很显然指向null
Object.prototype.__proto__ === null
为什么是null呢,你可以理解为有始有终,也可以理解为原型链必须要结束,不可能限循环下去。
A的原型链:
__proto__存在于每个对象中,而prototype只能存在于函数里,函数呢,又是特殊的对象,那么函数也是有__proto__的。那现在我们在以A这个构造函数,来了解其原型链,经过上面的分析,那A的原型链应该很简单了。
A.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
A的原型链写完了,那接着写Function的原型链:
Function的原型链:
Function.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
注意:Function的__proto__有点特别,因为它是指向Function.prototype,因为Function的构造函数就是Function。
如果我们将a的__proto__指向另一个对象b(let b = {}),而不是A.prototype了,那这个原型链该如何显示呢?如下所示:
a.__proto__ === b
b.__proto__ === Object.prototype
Object.prototype.__proto__ === null