首页 > 编程知识 正文

原型和原型链(js原型和原型链面试题)

时间:2023-05-03 16:26:45 阅读:82115 作者:550

前言

继承是我们前端必须熟悉的知识点。 以前的很多前端对继承的实现和应用没有整体的把握。 究其原因无非是两个:

ECMAScript继承的实现方式与其他基于类的实现继承的面向对象(Object Oriented )语言不同。 即使一知半解地知道如何在工作中实现继承,写逻辑代码也一点也不晚。 无论如何,建议尽快了解继承的实现和应用。 否则,你可能会像你的印章一样,——流下没有技术的眼泪。

接下来我将尽可能清楚地继承这个概念,并结合相关经典文字进行辅助说明。

在谈ECMAScript继承的概念之前,我先谈一下类和原型的概念。

类和原型

等级

在讲述ECMAScript继承的概念之前,请先阐述以下概念。 如果接触过Java或c,就会发现Java(c )的继承都是基于类的继承。

类:是基于面向对象(Object Oriented )语言(称为类型)的信息封装的基础。 每个类都包含一组数据说明和传递操作数据或消息的函数。 类的实例称为对象。

类:描述了代码的组织结构,它是软件中真实世界问题区域的建模方法。

类的概念在这里不扩展。 有兴趣的同学可以自己查书。 接下来,让我们将焦点放在原型和原型链上。

原型机

由于JavaScript这个语言没有类的概念,所以JavaScript是基于原型的继承而不是基于类的继承。 (主要参考自语言原型(prototype )继承机制。

注: ES6的class关键字和OO语言的类概念不同。 稍后说明。 ES6的class也在内部基于原型实现的继承。

JavaScript之所以使用原型作为放弃类实现继承的基础,是因为基于原型的继承在概念上比基于类的继承更简单。 首先,要明确的是,类的目的是实例化对象,而JavaScript可以直接从对象的文字语法中创建对象。

每个函数都有prototype属性。

对于通过函数new出现的所有对象,__proto__都指向该函数的prototype。

yhdej想使用对象(或数组)的功能时:如果对象本身具有该功能,则直接使用; 如果此对象本身没有此功能,请去__proto__查找。

1. prototype [显式原型]

prototype是只有函数才有的显式原型属性。

每个函数都有一个名为prototype的属性,该属性在创建后指向函数的原型对象。 (用Function.prototype.bind方法构建的函数是例外,没有prototype属性。) .

prototype是一个指针,指向对象。 例如,Array.prototype指的是一个名为Array的函数原型对象。

在控制台上打印console.log(array.prototype )的方法有很多。 这些方法全部事先嵌入到JavaScript中,直接调用即可。 我把两个特别的属性constructor和__proto__标记为红色。 这两个属性接下来谈。

现在,写函数。

当我写一个叫noWork的方法时,它自动创建了一个prototype指针属性(指向原型对象)。 中指定的原型对象将自动获取构造函数。 细心的同学一定注意到了constructor指的是noWork。

no work.prototype.constructor===no work//true

//某个函数的原型对象的构造函数就是该函数本身

您知道打印在tips:图上的Array的明确原型对象中的这些方法吗? 了解序列也是非常重要的部分哦~咳嗽,这是考试的重点。

2. __proto__[隐式原型]

prototype并不难理解,__proto__比prototype要复杂一些。 但是当yhdej理解的时候,你会发现这个过程真的很有趣。 让我们来谈谈__proto__。

其实这个属性指的是` [[prototype] `,但是` [ prototype ] `是内部属性,我们无法访问,所以使用` __proto__ `进行访问。

先定义一下绕弯子:

__proto__创建了对象

构造函数的显式原型。

我们现在还是使用 noWork 这个例子来说。我们发现 noWork 原型对象中还有另一个属性 __proto__。

我们先打印这个属性:

我们发现这个 __proto__ 指向的是 Object.prototype。

我听到有人在问为什么?

因为这个 __proto__.constructor 指向的是 Object。我们知道:一个函数的原型对象的构造函数是这个函数本身。所以这个 __proto__.constructor 指向的是 Object.prototype.constructor。进而 __proto__ 指向的是 Object.prototype。 至于为什么是指向Object?因为所有的引用类型默认都是继承Object。

作用

显式原型:用来实现基于原型的继承与属性的共享。隐式原型:构成原型链,同样用于实现基于原型的继承。 举个例子,当我们使用 noWork 这个对象中的 toString() 属性时,在 noWork 中找不到,就会沿着 __proto__ 依次查找。

3. new 操作符

当我们使用 new 操作符时,生成的实例对象拥有了 __proto__属性。即在 new 的过程中,新对象被添加了 __proto__ 并且链接到构造函数的原型上。

new 的过程

新生成了一个对象链接到原型绑定 this返回新对象

Function.__proto__===Function.prototype

难道这代表着 Function 自己产生了自己? 要说明这个问题我们先从 Object 说起。

我们知道所有对象都可以通过原型链最终找到 Object.prototype ,虽然 Object.prototype 也是一个对象,但是这个对象却不是 Object 创造的,而是引擎自己创建了 Object.prototype 。 所以可以这样说:

所有实例都是对象,但是对象不一定都是实例。

接下来我们来看 Function.prototype 这个特殊的对象:

打印这个对象,会发现这个对象其实是一个函数。我们知道函数都是通过 newFunction()生成的,难道 Function.prototype 也是通过 newFunction() 产生的吗?这个函数也是引擎自己创建的。

首先引擎创建了 Object.prototype ,然后创建了 Function.prototype ,并且通过 __proto__ 将两者联系了起来。

这就是为什么 Function.prototype.bind() 没有 prototype 属性。因为 Function.prototype 是引擎创建出来的对象,引擎认为不需要给这个对象添加 prototype 属性。

对于为什么 Function.__proto__ 会等于 Function.prototype ?

我看到的一个解释是这样的:

其他所有的构造函数都可以通过原型链找到 Function.prototype ,并且 functionFunction() 本质也是一个函数,为了不产生混乱就将 functionFunction() 的 __proto__ 联系到了 Function.prototype 上。

公众号:Web前端Talk

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。