Javascript 原型、原型链、prototype以及__proto__详解

2023-10-29

一、 普通对象与函数对象

JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象和函数对象,Object ,Function 是JS自带的函数对象。下面举例说明

function f1(){};
 var f2 = function(){};
 var f3 = new Function('str','console.log(str)');

 var o3 = new f1();
 var o1 = {};
 var o2 =new Object();

 console.log(typeof Object); //function
 console.log(typeof Function); //function
 console.log(typeof o1); //object
 console.log(typeof o2); //object
 console.log(typeof o3); //object
 console.log(typeof f1); //function
 console.log(typeof f2); //function
 console.log(typeof f3); //function 

在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object 也都是通过 New Function()创建的。

二、原型对象

在JavaScript 中,每当定义一个对象(函数)时候,对象中都会包含一些预定义的属性。其中函数对象的一个属性就是原型对象 prototype。注:普通对象没有prototype,但有__proto__属性。

原型对象其实就是普通对象(Function.prototype除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性))。看下面的例子:

 function f1(){};
 console.log(f1.prototype) //Object {}
 console.log(typeof f1.prototype) //object
 console.log(typeof Function.prototype)//function,这个特殊
 console.log(typeof Object.prototype) // object
 console.log(typeof Function.prototype.prototype) //undefined

从这句console.log(f1.prototype) //Object {} 的输出就结果可以看出,f1.prototype就是f1的一个实例对象。就是在f1创建的时候,创建了一个它的实例对象并赋值给它的prototype,基本过程如下:
var temp = new f1();
f1. prototype = temp;

所以,Function.prototype为什么是函数对象就迎刃而解了,上文提到凡是new Function ()产生的对象都是函数对象,所以temp1是函数对象。
var temp1 = new Function ();
Function.prototype = temp1;

那原型对象是用来做什么的呢?主要作用是用于继承。举了例子:

var person = function(name){
   this.name = name
  };
  person.prototype.getName = function(){
     return this.name; 
  }
  var zjh = new person(‘zhangjiahao’);
  zjh.getName(); //zhangjiahao

从这个例子可以看出,通过给person.prototype设置了一个函数对象的属性,那有person实例(例中:zjh)出来的普通对象就继承了这个属性。具体是怎么实现的继承,就要讲到下面的原型链了。

三、原型链

JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype。以上面的例子为例:

console.log(zjh.__proto__ === person.prototype); //true

同样,person.prototype对象也有__proto__属性,它指向创建它的函数对象(Object)的prototype

console.log(person.prototype.__proto__ === Object.prototype); //true

继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null

  console.log(Object.prototype.__proto__) //null

我们把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。如下图:
原型链

这样也解释了为什么在原型prototype中设置的属性可以被实例对象继承。当在实例对象中访问某个属性时,先在该对象内查找,若找不到,则通过原型链向它的上一级查找,实例对象的上一级就是创建该实例的函数对象的原型对象,也就是本例中的person.prototype。所以原型prototype中的属性可以被实例对象继承的原因
四、内存结构图

为了更加深入和直观的进行理解,下面我们画一下上面的内存结构图:
这里写图片描述
画图约定:
这里写图片描述

疑点解释:
1.Object.__proto__ === Function.prototype // true
Object是函数对象,是通过new Function()创建,所以Object.__proto__指向Function.prototype。

2.Function.__proto__ === Function.prototype // true
Function 也是对象函数,也是通过new Function()创建,所以Function.__proto__指向Function.prototype。

Function是自己创建自己。

3.Function.prototype.__proto__ === Object.prototype //true
其实这一点我也有点困惑,不过也可以试着解释一下。
Function.prototype是个函数对象,理论上他的__proto__应该指向 Function.prototype,就是他自己,自己指向自己,没有意义。
JS一直强调万物皆对象,函数对象也是对象,给他认个祖宗,指向Object.prototype。Object.prototype.__proto__ === null,保证原型链能够正常结束

五、constructor

原型对象prototype中都有个预定义的constructor属性,用来引用它的函数对象。这是一种循环引用

  person.prototype.constructor === person //true
  Function.prototype.constructor === Function //true
  Object.prototype.constructor === Object //true

上面的内存结构图:
这里写图片描述

有两点需要注意:
(1)注意Object.constructor=Function;//true 本身Object就是Function函数构造出来的
(2)如何查找一个对象的constructor,就是在该对象的原型链上寻找碰到的第一个constructor属性所指向的对象Function.constructor
=Function
person.construcor === Function

六、总结

1.原型和原型链是JS实现继承的一种模型。
2.原型链的形成是真正是靠__proto__ 而非prototype

要深入理解这句话,我们再举个例子,看看前面你真的理解了吗?

  var animal = function(){};
  var dog = function(){};

  animal.price = 2000;//
  dog.prototype = animal;
  var tidy = new dog();

  console.log(dog.price) //undefined
  console.log(tidy.price) // 2000

为什么呢?画一下内存图:
这里写图片描述

这说明什么问题呢,执行dog.price的时候,发现没有price这个属性,虽然prototype指向的animal有这个属性,但它并没有去沿着这个“链”去寻找。同样,执行tidy.price的时候,也没有这个属性,但是__proto__指向了animal,它会沿着这个链去寻找,animal中有price属性,所以tidy.price输出2000。由此得出,原型链的真正形成是靠的__proro__,而不是prototype。
因此,如果在这样指定dog.__proto__ = animal。那dog.price = 2000。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Javascript 原型、原型链、prototype以及__proto__详解 的相关文章

随机推荐

  • 基于springboot+vue民宿管理系统+数据库(附源码,说明文档)

    文章目录 开发环境 后端 前端 数据库 系统架构 管理员 用户用例 主要功能 用户功能模块 管理员功能模块 商家用户功能模块 前台首页功能模块 今天为大家带来的是 基于springboot vue民宿管理系统 开发环境 后端 开发语言 Ja
  • 理解线性回归(一)——回归的思想

    理解线性回归 一 回归的思想 1 经典的线性回归 之前介绍的LR回归和SVM算法本质上都和回归有写关联 尤其是LR回归算法 回归的目的是预测数值型的目标值 其核心部分和我们中小学时候学习到的线性拟合是一样的 就是说 假如我们能够建立了回归背
  • 刷脸支付三大优势让人回归万物本源

    3D人脸识别技术已实现检测人脸是否为活体 杜绝图片或视频破解 其高精度 高效率 高安全性催生刷脸支付 刷脸门禁 刷脸乘车 刷脸登机等应用落地 在5G AI引爆的万物互联未来 人回归智能万物的中心 脸成为无缝连接所有生活场景的重要途径 近期大
  • Python及pip安装与报错处理【pip永久换源】

    有帮助的话请点个赞吧 文章目录 安装新版本Python Linux系统 以Ubuntu16 04为例 Windows系统 Win10 pip换源 Linux系统 Windows系统 安装新版本Python Linux系统 以Ubuntu16
  • 微信小程序 引入字体图标 字体 使用base64解决字体请求问题

    在做公司的项目的时候 引入了奥森字体图标 控制台对这个url有报错提示 虽然字体显示正常 但还是想解决这个烦人的报错 试过加载目录中的fontawesome webfont ttf 静态资源但是加载不上 最后把ttf字体转换成base64格
  • 「司库立方」获数亿元C轮融资,持续聚焦司库赛道,引领行业变革

    今天 头部司库玩家 司库立方 宣布成功获得数亿元C轮融资 本轮融资由云晖资本领投 中信建投资本 贵阳创投 神骐资本 58产业基金 跟投 老股东信天创投持续追投 本轮融资资金主要用于迭代产品 加强市场推广 提升客户服务和体验 进一步扩大公司在
  • 史上最简单的SpringCloud教程

    在微服务架构中 根据业务来拆分成一个个的服务 服务与服务之间可以相互调用 RPC 在Spring Cloud可以用RestTemplate Ribbon和Feign来调用 为了保证其高可用 单个服务通常会集群部署 由于网络原因或者自身的原因
  • CAD平台开发和基于此平台的二次开发(数据库部分)

    CAD平台开发分为两大部分 一是底层开发 即CAD数据库的开发 底层类和结构 二是上层开发 界面和功能实现 本人目前在一个开发CAD平台的公司 工作 目前主要接触的是上层开发这一部分 没有底层开发的部分的代码 只有编号的底层数据库的DLL
  • MIPI DSI AP介绍(一)FPGA

    MIPI DSI AP介绍 一 FPGA MIPI DSI Mobile Industry Processor Interface Display Serial Interface 是一种用于移动设备显示的串行接口协议 它的主要特点是高带宽
  • 深入浅出PID控制算法(二)——PID算法离散化和增量式PID算法原理及Matlab仿真

    文章目录 1 PID算法离散化 1 1 位置式PID算法 1 2 增量式PID算法 2 PID编程实现及控制仿真 3 PID调参过程 3 1 确定比例系数Kp 3 2 确定积分时间常数Ti 3 3 确定微分时间常数Td 3 4 系统空载 带
  • C++ 修改/覆盖指定位置的文件内容或者从某个位置开始截断文件

    最新在进行文件方面的功能开发 遇到个这样的问题 1 文件读到中间 然后进行一些修改 2 然后将文件从修改后的地方截断 本以为这是个简单的操作 却花费了好大的功夫 网上并没有这样的例子 一通尝试 现在终于圆满解决了 特地记录一下 方便后来人
  • Linux 系统告警报“ inode”空间不足引起数据库启动失败

    启动数据库报错 错误如下 SQL gt startup nomount pfile oracle admin ecis ecis ora1 ORA 27154 post wait create failed ORA 27300 OS sys
  • IPP简介及windows下安装说明

    IPP简介及windows下安装说明 专栏目录 说明 一 IPP简介 二 windows7和windows10下安装说明 1 windows10下安装 1 oneAPI集成安装 2 单独下载安装 2 windows7安装 1 2021之前版
  • JPEG编码学习

    常见有损的图像格式有 JPEG WebP 常见无损的图像格式有 PNG BMP GIF JPEG编码 JPEG编码流程 例程GitHub地址 python jpeg encoder 另一个demo 也可以试一试 Image Compress
  • pythone二级题库 + 刷题软件 (超详细解析,看完必过) 第十一套

    刷题软件 模拟python二级考试 操作题刷题软件 1 计算机完成一条指令所花费的时间称为一个 A 指令周期 B 存取周期 C 执行速度 D 执行时序 一般把计算机完成一条指令所花费的时间统称为一个指令周期 指令周期越短 指令执行就越快 2
  • 机器学习——深度学习(Deep Learning)

    Deep Learning是机器学习中一个非常接近AI的领域 其动机在于建立 模拟人脑进行分析学习的神经网络 最近研究了机器学习中一些深度学习的相关知识 本文给出一些很有用的资料和心得 Key Words 有监督学习与无监督学习 分类 回归
  • minikube实践篇(Deprecated!!!)

    1 安装minikube 在油管上观看了TechWorld with Nana的频道 发现minikube对开发人员友好 在本地也不用开集群了 其实就像当于是开了一个虚拟机 我准备直接在vmware中安装 但是安装minikube并不是那么
  • AJAX学习笔记4解决乱码问题

    AJAX学习笔记3练习 biubiubiu0706的博客 CSDN博客 在Tomcat10来说 AJAX GET或者POST接收响应都不存在乱码问题 对于Tomcat9来说 前端测试代码
  • 【MXNet C++】人脸检测与口罩识别(提供c++源码、mxnet模型文件、win演示程序安装包)

    2020 03 31更新 公开源码和模型 2020 03 09更新 公开win安装包程序 如有需 可私信 一个用以检测戴口罩人脸的工程 基于MXNet OpenCV开源框架 使用C 语言实现 工程代码 Github 安装程序 百度网盘 提取
  • Javascript 原型、原型链、prototype以及__proto__详解

    一 普通对象与函数对象 JavaScript 中 万物皆对象 但对象也是有区别的 分为普通对象和函数对象 Object Function 是JS自带的函数对象 下面举例说明 function f1 var f2 function var f