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

news/2024/5/15 5:00:06

来讲一讲原型链

原型链只存在于函数之中

四个规则

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.mrgr.cn/p/13081078

相关文章

RSTP环路避免实验(华为)

思科设备参考:RSTP环路避免实验(思科) 一,技术简介 RSTP (Rapid Spanning Tree Protocol) 是从STP发展而来 • RSTP标准版本为IEEE802.1w • RSTP具备STP的所有功能,可以兼容STP运行 • RSTP和STP有所不同 减少了…

TitanIDE与传统 IDE 比较

与传统IDE的比较 TitanIDE 和传统 IDE 属于不同时代的产物,在手工作坊时代,一切都是那么的自然,开发者习惯 Windows 或 MacOS 原生 IDE。不过,随着时代的变迁,软件行业已经步入云原生时代,TitanIDE 是顺应…

使用MergeKit创建自己的专家混合模型:将多个模型组合成单个MoE

由于Mixtral的发布,专家混合(MoE)架构在最近几个月变得流行起来。虽然Mixtral和其他MoE架构是从头开始预训练的,但最近出现了另一种创建MoE的方法:Arcee的MergeKit库可以通过集成几个预训练模型来创建moe。这些人通常被称为frankenMoEs或MoErges,以区别于预先训练的MoEs。 …

Redis命令-List命令

4.6 Redis命令-List命令 Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。 特征也与LinkedList类似: 有序元素可以重复插入和删除快查询速度一般 常用来存储一个有序数据&#xff…

前端学习-UI框架学习-Bootstrap5-011-徽章(Badges)

菜鸟教程链接 <template><div class="container mt-3"><h3>徽章<span class="badge bg-success">new</span></h3><h3>药丸形状徽章<span class="badge bg-danger rounded-pill">new</span&g…

Acwing 1491. 圆桌座位

https://www.acwing.com/problem/content/1493/输入样例1: 4 1 1 2 输出样例1: 2 输入样例2: 10 5 1 2 3 4 5 6 7 8 9 10 输出样例2: 112512#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> PII; const LL MAXN=1e…

多源统一视频融合可视指挥调度平台VMS/smarteye系统概述

系统功能 1. 集成了视频监控典型的常用功能&#xff0c;包括录像&#xff08;本地录像、云端录像&#xff08;录像计划、下载计划-无线导出&#xff09;、远程检索回放&#xff09;、实时预览&#xff08;PTZ云台操控、轮播、多屏操控等&#xff09;、地图-轨迹回放、语音对讲…

网络:udptcp套接字

目录 协议 网络传输基本流程 网络编程套接字 udp套接字编程 udp相关代码实现 sock函数 bind函数 recvfrom函数 sendto函数 udp执行指令代码 popen函数 udp多线程版收发消息 tcp套接字编程 tcp套接字代码 listen函数 accept函数 read/write函数 connect函数 recv/…

3.29

这几天GGrun兽性大发,D真和int_R都受到了非人的礼遇(指猜拳决斗) GGrun:来!进行决斗!(指猜拳) (猜拳输了) GGrun:hinhin,baby~~ man~~(搓手,跃跃欲试) (但GGrun的主要攻击对象是CTH)二调下来了,被文化课薄纱了 但GGrun这个出生数学考了149,在这里强烈谴责GGru…

verilog语言学习-HDLBits

基本逻辑: and  a&b  与  同为1时输出1or   a|b  或  有一个为1输出1xor   a^b  异或  ab不同时输出1nand   !(a&b)  与非  not and a与b再取反nor   ~(a|b)  或非  a或b再取反xnor  a~^b  同或  ab相同时输出1anotb  a&(…

fastadmin学习04-一键crud

FastAdmin 默认内置一个 test 表&#xff0c;可根据表字段名、字段类型和字段注释通过一键 CRUD 自动生成。 create table fa_test (id int unsigned auto_increment comment ID primary key,user_id int(10) default 0 null…

Web Components使用(一)

在使用Web Components之前&#xff0c;我们先看看上一篇文章Web Components简介&#xff0c;其中提到了相关的接口、属性和方法。 正是这些接口、属性和方法才实现了Web Components的主要技术&#xff1a;Custom elements&#xff08;自定义元素&#xff09;、Shadow DOM&#…

百度智能云千帆,产业创新新引擎

本文整理自 3 月 21 日百度副总裁谢广军的主题演讲《百度智能云千帆&#xff0c;产业创新新引擎》。 各位领导、来宾、媒体朋友们&#xff0c;大家上午好。很高兴今天在石景山首钢园&#xff0c;和大家一起沟通和探讨大模型的发展趋势&#xff0c;以及百度最近一段时间的思考和…

2.7、创建列表(List)

概述 列表是一种复杂的容器&#xff0c;当列表项达到一定数量&#xff0c;内容超过屏幕大小时&#xff0c;可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集&#xff0c;例如图片和文本。在列表中显示数据集合是许多应用程序中的常见要求&#xff08;如通讯录、…

数据可视化是如何与智慧交通相结合的?

在当今社会,数据已成为信息时代的关键资源,而数据可视化则是将这些庞杂的数据转换为易于理解和分析的图形和图表的过程。随着城市化进程的加快,交通拥堵、安全管理、环境监测等问题日益凸显,智慧交通系统的构建成为了解决这些问题的关键,而数据可视化在这一过程中发挥了不…

Web Audio API 第3章 音量和响度

此章介绍的科普物理声音知识相当有用,编程的反而涉及的少音量和响度Loudness 响度 注:根据《韦氏词典》,响度是“一种声音的属性,它决定了所产生的听觉感觉的大小,主要取决于所涉及声波的振幅。”这意味着响度取决于你大脑中感知到的声音。而是声音对你来说有多大。这是主…

在 kubernetes 环境下如何优雅扩缩容 Pulsar

背景 在整个大环境的降本增效的熏陶下,我们也不得不做好应对方案。 根据对线上流量、存储以及系统资源的占用,发现我们的 Pulsar 集群有许多的冗余,所以考虑进行缩容从而减少资源浪费,最终也能省一些费用。 不过在缩容之前很有必要先聊聊扩容,Pulsar 一开始就是存算分离的…

成都市酷客焕学新媒体科技有限公司:实现品牌的更大价值!

成都市酷客焕学新媒体科技有限公司专注于短视频营销&#xff0c;深知短视频在社交媒体中的巨大影响力。该公司巧妙地将品牌信息融入富有创意和趣味性的内容中&#xff0c;使观众在轻松愉悦的氛围中接受并传播这些信息。凭借独特的创意和精准的营销策略&#xff0c;成都市酷客焕…

深度学习故障诊断实战 | 数据预处理之创建Dataloader数据集

前言 本期给大家分享介绍如何用Dataloader创建数据集 背景 示例代码 from torch import nn import torch import os import numpy as np import pandas as pd import matplotlib.pyplot as plt import time import torch.functional as F from sklearn.manifold import TSNE…

Sysbench安装与使用

Sysbench Sysbench安装curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.deb.sh | sudo bash sudo apt -y install sysbench sysbench --versionSysbench使用 内存测试 查看内存帮助信息 sysbench memory help # 查看内存帮助信息 sysbench 1.0…