原型链-(前端面试 2024 版)

来讲一讲原型链

原型链只存在于函数之中

四个规则

1、引用类型,都具有对象特性,即可自由扩展属性。

2、引用类型,都有一个隐式原型 __proto__ 属性,属性值是一个普通的对象。

3、引用类型,隐式原型 __proto__ 的属性值指向它的构造函数的显式原型 prototype 属性值

4、当你试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么它会去它的隐式原型 __proto__(也就是它的构造函数的显式原型 prototype)中寻找

四个知识点

  • Object 是所有对象的爸爸,所有对象都可以通过 __proto__ 找到它
  • Function 是所有函数的爸爸,所有函数都可以通过 __proto__ 找到它
  • 函数的 prototype 是一个对象
  • 对象的 __proto__ 属性指向原型, __proto__ 将对象和原型连接起来组成了原型链

const obj = {};
const arr = [];
const fn = function() {}obj.__proto__ == Object.prototype // true
arr.__proto__ === Array.prototype // true
fn.__proto__ == Function.prototype // true

new 做了什么

var obj = new F();
//  做了什么
var obj  = {};
obj.__proto__ = F.prototype;
F.call(obj);

第一行,我们创建了一个空对象obj;

第二行,我们将这个空对象的__proto__成员指向了F函数对象prototype成员对象;

第三行,我们将F函数对象的this指针替换成obj,然后再调用F函数.

我们可以这么理解: 以 new 操作符调用构造函数的时候,函数内部实际上发生以下变化:

1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。

2、属性和方法被加入到 this 引用的对象中。

3、新创建的对象由 this 所引用,并且最后隐式的返回 this.

prototype和__proto__

1. __proto__是每个对象都有的一个属性,而prototype是函数才会有的属性。

2. __proto__指向的是当前对象原型对象,而prototype指向的,是以当前函数作为构造函数构造出来的对象原型对象
你的__proto__来自你构造函数的prototype;所有对象字面量都是通过Object()构造出来的,换言之,对象字面量__proto__ 属性都指向Object.prototype

  • prototype: 显式原型

每一个函数在创建之后都会拥有一个名为prototype的属性,这个属性指向函数的原型对象。

通过Function.prototype.bind方法构造出来的函数是个例外,它没有prototype属性
JavaScript中任意对象都有一个内置属性[[prototype]],在ES5之前没有标准的方法访问这个内置属性,但是大多数浏览器都支持通过__proto__来访问。ES5中有了对于这个内置属性标准的Get方法Object.getPrototypeOf().

Object.prototype 这个对象是个例外,它的__proto__值为null

隐式原型指向创建这个对象的函数(constructor)的prototype

作用是什么:显式原型的作用:用来实现基于原型的继承与属性的共享。
 


 

  • __ proto__: 隐式原型

隐式原型的作用:构成原型链,同样用于实现基于原型的继承。举个例子,当我们访问obj这个对象中的x属性时,如果在obj中找不到,那么就会沿着__proto__依次查找。

__proto__的指向:__proto__的指向到底如何判断呢?根据ECMA定义 'to the value of its constructor’s "prototype" ' ----指向创建这个对象的函数的显式原型。所以关键的点在于找到创建这个对象的构造函数,接下来就来看一下JS中对象被创建的方式,一眼看过去似乎有三种方式:(1)对象字面量的方式 (2)new 的方式 (3)ES5中的Object.create() 但是我认为本质上只有一种方式,也就是通过new来创建。为什么这么说呢,首先字面量的方式是一种为了开发人员更方便创建对象的一个语法糖,本质就是 var o = new Object(); o.xx = xx;o.yy=yy; 再来看看Object.create(),这是ES5中新增的方法,在这之前这被称为原型式继承,

构造函数的prototype和其实例的__proto__是指向同一个地方的,这个地方就叫做原型对象

Function和Object

构造函数的prototype和其实例的__proto__是指向同一个地方的,咱们可以来验证一下

  • 函数是Function构造函数的实例
  • 对象是Object构造函数的实例

那Function构造函数和Object构造函数他们两个又是谁的实例呢?

  • function Object()其实也是个函数,所以他是Function构造函数的实例
  • function Function()其实也是个函数,所以他也是Function构造函数的实例,没错,他是他自己本身的实例


 

console.log(Function.prototype === Object.__proto__) // true
console.log(Function.prototype === Function.__proto__) // true

constructor和prototype是成对的,你指向我,我指向你

function fn() {}console.log(fn.prototype) // {constructor: fn}
console.log(fn.prototype.constructor === fn) // true

原型链

什么是原型链呢?其实俗话说就是:__proto__的路径就叫原型链

原型继承


说到原型,就不得不说补充一下原型继承这个知识点了,原型继承就是,实例可以使用构造函数上的prototype中的方法

instanceof

作用:判断B的prototype是否在A的原型链上


A instanceof B

【JS】图解原型链相关练习题,带你彻底搞懂原型链!!!(这可能是掘金画原型链画的最正的😃) - 掘金

第一题

主要坑是 f的构造函数是 F F的构造函数是Obj,

f的所有方法从以下找

f.__proto__ === F.protyotype F.__proto__ === obj.protyotype obj.proto=== null

F的所有方法从以下找

F.__proto__ === Function.protyotype Function.__proto__ === obj.protyotype obj.proto=== null

var F = function() {};Object.prototype.a = function() {console.log('a');
};Function.prototype.b = function() {console.log('b');
}var f = new F();f.a();
f.b();F.a();
F.b();

第二题

b的所有方法从以下找

b.__proto__ === A.protyotype A.proto=== obj.protyotype obj.proto=== null

c的所有方法从以下找

b.__proto__ === A.protyotype A.proto=== obj.protyotype obj.proto=== null

本体核心是每次new时使用的都是构造函数最新的prototype ,老的构造函数引用老的prototype 并不会被覆盖

var A = function() {};
A.prototype.n = 1;
var b = new A();
A.prototype = {n: 2,m: 3
}
var c = new A();console.log(b.n);
console.log(b.m);console.log(c.n);
console.log(c.m);

第三题

函数的构造函数一定是Function 对象的构造函数 可能是obj 也可能是new Function

var foo = {},F = function(){};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b';console.log(foo.a);
console.log(foo.b);console.log(F.a);
console.log(F.b);

第四题

new 的时候会函数内this会重新赋值进行覆盖

function A() {}
function B(a) {this.a = a;
}
function C(a) {if (a) {this.a = a;}
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;console.log(new A().a); 
console.log(new B().a);
console.log(new C(2).a);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/577399.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue——案例01(查询用户)

一、案例实现页面 二、案例实现效果 1. 查询效果 2. 年龄升序 3. 年龄降序 4. 原顺序 三、案例实现思路 1. 定义界面所需标签样式 <div id"app"><h2>查询用户:</h2><input type"text" placeholder"请输入名字"/><b…

代码随想录算法训练营第35天| 435. 无重叠区间、763.划分字母区间、56. 合并区间

435. 无重叠区间 题目链接&#xff1a;无重叠区间 题目描述&#xff1a;给定一个区间的集合 intervals &#xff0c;其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量&#xff0c;使剩余区间互不重叠 。 解题思想&#xff1a; 这道题目和射气球很像。 *“需…

rust使用Command库调用cmd命令或者shell命令,并支持多个参数和指定文件夹目录

想要在不同的平台上运行flutter doctor命令&#xff0c;就需要知道对应的平台是windows还是linux&#xff0c;如果是windows就需要调用cmd命令&#xff0c;如果是linux平台&#xff0c;就需要调用sh命令&#xff0c;所以可以通过cfg!实现不同平台的判断&#xff0c;然后调用不同…

代码随想录算法训练营第二十四天|77.组合、216.组合Ⅲ

文档链接&#xff1a;https://programmercarl.com/ LeetCode77.组合 题目链接&#xff1a;https://leetcode.cn/problems/combinations/ 思路&#xff1a; 回溯三部曲&#xff1a; 第一步&#xff1a;确定函数返回值和参数类型 第二步&#xff1a;确定终止条件 第三步&a…

JUC/多线程的基本使用(一)

一、基本使用 Thread、Runnable、FutureTask Java多线程-CSDN博客https://blog.csdn.net/m0_71534259/article/details/132381495?spm1001.2014.3001.5501 二、查看进程线程的方法 windows 任务管理器可以查看进程和线程数&#xff0c;也可以用来杀死进程 tasklist 查看…

ICLR2024:南洋理工发布!改几个参数就为大模型注入后门

随着大语言模型&#xff08;LLMs&#xff09;在处理自然语言处理&#xff08;NLP&#xff09;相关任务中的广泛应用&#xff0c;它们在人们日常生活中的作用日益凸显。例如&#xff0c;ChatGPT等模型已被用于各种文本生成、分类和情感分析任务。然而&#xff0c;这些模型潜在的…

上位机图像处理和嵌入式模块部署(qmacvisual非opencv算法编写)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 我们都知道&#xff0c;qmacvisual本身依赖于qtopencv的实现。大部分的界面都是依赖于qt的实现。图像算法部分&#xff0c;也是大部分都依赖于open…

RockChip Android8.1 Settings

一:Settings一级菜单 1、AndroidManifest.xml 每个APP对应都有一个AndroidManifest.xml,从该文件入手分析最为合适。 packages/apps/Settings/AndroidManifest.xml 根据<category android:name="android.intent.category.LAUNCHER" />可找到当前当前APP a…

【计算机网络篇】数据链路层(4.2)可靠传输的实现机制

文章目录 &#x1f354;可靠传输的实现机制⭐停止 - 等待协议&#x1f5d2;️注意 &#x1f50e;停止 - 等待协议的信道利用率&#x1f5c3;️练习题 ⭐回退N帧协议&#x1f388;回退N帧协议的基本工作流程&#x1f50e;无传输差错的情况&#x1f50e;超时重传的情况&#x1f5…

服务器被挖矿了怎么办,实战清退

当我们发现服务器资源大量被占用的时候&#xff0c;疑似中招了怎么办 第一时间重启服务是不行的&#xff0c;这些挖矿木马一定是会伴随着你的重启而自动重启&#xff0c;一定时间内重新霸占你的服务器资源 第一步检查高占用进程 top -c ps -ef 要注意这里%CPU&#xff0c;如果…

CavalierContours 二维线操作

CavalierContours 二维线操作 2D polyline library for offsetting, combining, etc. 用于偏移、交并补等组合等操作的 2D 多折段线库。 Polyline Structure 多段线结构 Polylines are defined by a sequence of vertexes and a bool indicating whether the polyline is cl…

如何在 Oracle 中使用 CREATE SEQUENCE 语句

在本文中&#xff0c;我们将讨论 Oracle CREATE SEQUENCE 语句&#xff0c;其主要目的是提供一种可靠的方法来生成唯一且连续的数值&#xff0c;通常用于数据库表中的主键字段。此功能对于维护数据完整性和效率、确保不同记录之间的标识符有序分配尤其重要。从本质上讲&#xf…