什么是原型链:JavaScript内置的继承方法被称为原型对象链,又称为原型对象继承。
在JavaScript语言中,每一个对象都有一个对应的原型对象,被称为 prototype 对象。定义在原型对象上的所有属性和方法,都能被派生对象继承。这就是JavaScript继承机制的基本设计。
- 在 JavaScript 中,所有的对象都有一个隐藏的 [[Prototype]] 属性,它要么是另一个对象,要么就是 null。
- 我们可以使用
obj.__proto__
访问它。 - 通过 [[Prototype]] 引用的对象被称为“原型”。
- 如果我们想要读取 obj 的一个属性或者调用一个方法,并且它不存在,那么 JavaScript 就会尝试在原型中查找它。
- 写/删除操作直接在对象上进行,它们不使用原型(假设它是数据属性,不是 setter)。
- 如果我们调用 obj.method(),而且 method 是从原型中获取的,this 仍然会引用
obj。因此,方法始终与当前对象一起使用,即使方法是继承的。
prototype对象的作用
定义所有实例对象共享的属性和方法,所以它也被称为实例对象的原型,而实例对象(new 一个对象)可以视作从prototype对象衍生出来的。
也可以直接将属性放到prototype上:
function Animal (name) {
this.name = name;
}
Animal.prototype.color = "white";
var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');
cat1.color === cat2.color// true
注意__proto__是 [[Prototype]] 的因历史原因而留下来的 getter/setter
初学者常犯一个普遍的错误,就是不知道__proto__ 和 [[Prototype]] 的区别。
请注意__proto__ 与内部的 [[Prototype]] 不一样。而且__proto__ 是 [[Prototype]] 的 getter/setter
1、每个对象都有一个__proto__属性,对象是由构造函数创建的,但是对象没有prototype,只有函数才有
2、new 一个对象 //构造函数
3、constructor 对象 // 析构函数,销毁对象,在JS中不需要,JS会自动销毁
“原型链”的作用
在于当读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。以此类推,如果直到最顶层的Object.prototype还是找不到,则返回undefined。
举个例子:
const obj = { name: 'jack' }
console.dir(obj) // 可以显示一个对象的所有属性和方法
可以看到,在我还没对obj做其他操作之前,obj已经有几个(隐式)属性(方法)了,比如 obj.valueOf、obj.toString、__proto__等。
当我们读取 obj.toString 时JS引擎会做这几步:
1. 看看 obj 对象本身有没有 toString 属性。没有就走到下一步。
2. 看看 obj.__proto__ 对象有没有 toString 属性,发现 obj.__proto__ 有 toString 属性,于是找到了
所以我们上面的 obj.toString 实际上就是在第 2 步中找到的 obj.__proto__.toString
假如,我们在第二步并没有找到 toString属性
3. 如果 obj.__proto__ 还没有,浏览器会继续查看 obj.__proto__.__proto__
4. 如果 obj.__proto__.__proto__ 也没有,那么浏览器会继续查看 obj.__proto__.__proto__.proto__
5. 直到找到 toString 或者 __proto__ 为 null。
整个过程,都是由__proto__组成的链子一直走的,这个链子就是原型链