编程技术文章分享与教程

网站首页 > 技术文章 正文

彻底理解Javascript原型链 js的原型和原型链是什么

hmc789 2024-11-10 10:33:48 技术文章 2 ℃

JS原型链是前端面试中的经典问题了,几乎所有前端面试或笔试都会考察应聘者对原型链的理解程度,同时这一块知识点也是JavaScript中的一个重点和难点。因为之前看红宝书JavaScript高级程序设计感觉里面讲的不是很透彻,所以今天就打算重新梳理总结一下。

首先,读者可以通过下图自我检测一下是否真正理解原型链:

如果看图能完全理解里面每一个箭头的,可以不用继续往下看了,你已经基本掌握原型链了;如果看图感觉箭头绕来绕去很复杂,也不用慌,看完这篇文章,你就能完全理解这张图了。

1.隐形原型和显性原型

在讲原型链之前,我们需要知道隐形原型(__proto__)和显性原型(prototype)这两个概念。

prototype

prototype属性,它是函数所独有的,它是指向函数的原型对象的一个指针,这个对象的用途就是包含所有实例对象共享的属性和方法(我们把这个对象叫做原型对象);

示例:

function Foo(){
}
Foo.prototype.name="martin";
let f1=new Foo();
let f2=new Foo();
console.log(f1.name); //martin
console.log(f2.name); //martin

可以看出,Foo函数原型对象上的属性和方法被每个实例所共享。

__proto__

__proto__ 是原型链查询的关键属性,它是指向对象构造函数原型对象的一个指针,它是对象独有的。

注意:函数中也有__proto__属性,因为函数是特殊的对象。?

function Foo(){
}
Foo.prototype.name="martin";
let f1=new Foo();
console.log(f1.__proto__ === Foo.prototype); //true

其中Foo是f1的构造函数,所以f1的隐形原型指向的是Foo的原型对象。

2.什么是原型链

每个对象都有一个隐形原型 __proto__ 属性,里面存的是一个指针,指针指向该对象构造函数的原型对象,而该原型对象也有一个__proto__属性,里面也存着一个指针,该指针指向该对象的构造函数的原型对象,通过这种方式形成了一条向上寻找的链条,这个链条就叫做原型链。

示例:

function Foo(){
}
let f1=new Foo();
console.log(f1.__proto__ === Foo.prototype); //true
console.log(Foo.prototype.__proto__===Object.prototype); //true
console.log(Object.prototype.__proto__===null); //true

其中f1的隐形原型指向其构造函数Foo的原型对象,且Foo原型对象的构造函数为内置构造函数Object(所有对象的基础构造函数),因此Foo.prototype的隐形原型指向Object的原型对象,最后Object.prototype的隐形原型指向null(这个指向记住就好,底层代码规定好的),这就是一条完整的原型链了,如下图:

3.关键指向要记住

在内置的函数和原型对象中,有几个关键指向或者说是容易混淆的指向我们要记住。

  • Function.__proto__===Function.prototype,也就是Function内置函数(所有函数的基础构造函数)的构造函数是它自己,因此隐形原型指向自己的原型对象
  • Object.__proto__===Function.prototype,这个很好理解,Object是对象的基本构造函数,毕竟它也是一个函数,因此它的构造函数就是Function了。
  • Object.prototype.__proto__===null,也就是说Object.prototype的隐形原型是null,但是要注意的是,这里并不代表Object.prototype的构造函数是null,但是说明null是原型链的顶端,这其实是JS一直以来的一个Bug,记住就行。

4.原型链的查找

原型链的查找其实就是通过隐形原型(__proto__)连接的各个对象构造函数的原型对象(prototype),从而去查找原型链上各个原型对象上是否存在查找的属性或者方法,那原型链的具体查找顺序又是如何呢?

原型链的查找顺序

先找实例对象中是否有查找的属性或方法,若有则直接返回,没有则一步步沿着原型链在上层的原型对象中查找。

示例:

function life() {
}
life.prototype.name="martin";
function person(){
}
person.prototype=new life();
person.prototype.constructor=person;
let student=new person();
console.log(student.name); //martin

这个例子中的实例student的name属性查找顺序如下图所示:

先查找student实例,发现没有name属性,则向原型链上一person.prototype对象中查找,发现也没有,则继续向上一层的life.prototype对象中查找,发现有name属性,则直接返回name的属性值并停止原型链的查找。

5.自测题

下面可以做几个自测题检验一下自己是否理解,如果不理解请再多看几遍文章开头的图。

A instanceof B是用来检测B的原型对象(B.prototype)是否在A的原型链上,如果存在返回true。

console.log(Function instanceof Function);
console.log(Function instanceof Object);
console.log(Object instanceof Object);
console.log(Object instanceof Function);
  • Function instanceof Function即Function.prototype是否在Function的原型链上

返回true

  • Function instanceof Object即Object.prototype是否在Function的原型链上

返回true

  • Object instanceof Object即Object.prototype是否在Object的原型链上

返回true

  • Object instanceof Function即Function.prototype是否在Object的原型链上

返回true

标签列表
最新留言