proto文件支持继承吗_关于ES6中继承的问题 B继承A B.__proto__ = A?

2023-11-04

B.__proto__.__proto__ 确实是 Function.prototype ,但首先它的原型是 A ,其原型的原型才是函数原型。因为定义在 A 上的静态方法 B 也要继承。

更新:

每一个对象都有原型,但是对象的原型并不一定是对象的构造函数的 prototype 属性。

我在这里先声明一下几个术语,前端届对原型的称呼一直比较混乱:对象:JS 中一切非原始值皆对象,函数也是对象的一种

原型:每个对象都有一个原型,原型本身也是一个普通的对象。

使用点操作符或者 [ ] 访问属性时,会先检查对象本身的属性,如果不存在则会检查对象的原型,如果还不存在则会继续检查对象原型的原型直到原型的尽头 Object.prototype ,它没有原型,它的原型是 null,这个就是所谓的原型链。

获取对象的原型可以用标准的 Object.getPrototypeOf(obj),或者非标准的 obj.__proto__, 以下我都用 Object.getPrototypeOf(obj).

对象的默认 toString, valueOf 方法都来自 Object.prototype。

函数:函数是一种特殊的对象,所以函数也有原型,通过 function 语句声明的函数的原型是 Function.prototype。函数的 call,apply,bind 方法都来自 Function.prototype 上。

构造函数:除了箭头函数外,普通函数都可以当作构造函数用,用法就是使用 new 操作符。

类:ES6 的类是一种特殊的函数,只能通过 new 操作符来使用,不能当普通函数来直接调用。

函数.prototype: 函数对象还有一个特殊的属性,名字叫 prototype。这个我们还是别叫 函数的原型 了吧,因为函数作为对象看待它本身确实是有原型的,所以我们叫它函数的prototype属性,以区别于函数的原型,即:Object.getPrototypeOf(fn) vs fn.prototype.

new 一个构造函数发生了什么:新建一个对象

把对象的原型指向构造函数的 prototype 属性

把对象当 this 运行一遍构造函数

什么是继承?JS 的继承发生在对象之间,而非类之间,就像现实中的儿子继承爸爸,不需要先有儿子类和爸爸类,让儿子类 extends 爸爸类然后实例化。JS 中的对象直接继承另一个对象。

JS 的继承是使用原型来实现的。对象属性查找会检查原型链,这就是继承概念的体现。

ES5 加入的 Object.create API 就是把一个对象当原型来创建另一个对象之用。

基于 prototype 的继承模拟基于 class 的继承:函数的 prototype 属性就是用来模拟基于 class 的继承的,否则只要能从一个对象构造另一个对象那 prototype 继承就有了。

当我们 new 一个 class/函数 时,其实我们是把 class/函数的prototype 属性当原型来构造新对象的。你把方法和属性定义在函数的prototype属性上,用起来和传统的类定义方法和字段一个感觉。

对象的构造器本质就是一个 constructor 属性,所以函数的 prototype.constructor 会自动回指到函数本身,以便 new 出来的对象能正确获取到构造器。

说的有点多,回到你的问题:

每一个对象都有原型,但是对象的原型并不一定是对象的构造函数的 prototype 属性。

且不说 constructor 属性并不是一个锁死的属性,JS 中的有些对象也并不一定存在一个构造器。var father = {money: 1000,house:'big house'};

// father 对象使用对象字面量定义,本质上和 new Object 一回事

// 所以 father 是用 Object 构造的

father.constructor === Object // 没问题

var son = Object.create(father);

son.money // 这里我们说 son 继承了 father 的所有属性

Object.getPrototypeOf(son) === father; // 毛得问题吧

son.constructor // 这玩意儿会是什么?

son.constructor === father.constructor; // 嗯,来自于父亲

如上代码展示,其实 JS 中对象的构造器不是在所有场合都合理且有意义。构造函数这个概念在基于 prototype 继承的体系里其实是不需要的,它是 JS 模拟基于类的继承加入的东西。

那么题主的问题到底出现在哪里呢?出现在这里:

class是语法糖,本质上还是个函数,因此B实际上是个函数,可以看作通过new Function创建出来的Function对象实例

class 是语法糖没错,本质是函数也没错,错在 class B 并不能看作是 new Function 构造出来的,class A 可以,但是 B 不行。因为 B extends A,B 是通过 A 构造出来的。你忘了,JS 继承的本质是对象继承。 class B extends A 这里隐含了两个 prototype 继承。 B.prototype 继承了 A.prototype, 同时 B 继承了 A。class A {

static p = 1;

}

class B extends A{}

B.p; // 1

Object.getPrototypeOf(B.prototype) === A.prototype; // true

Object.getPrototypeOf(B) === A; // true

//或者说用非标准属性表示 B.__proto__ === A

因为静态属性也是需要继承的,所以 B 并不是直接通过 new Function 构造出来的,B 是通过 A 作为原型构造出来的,即 B = Object.create(A); 这样 B 才能获得 A 上定义的静态属性和方法,才符合基于 class 的继承的表现。

所以,B.constructor 在这里并没有很符合实际的意义,并不存在一个函数它把 B 构造了出来。从原型的角度看待就不存在这种问题,B 用了 A 当原型,A 用了 Function.prototype 当原型,仅此而已。

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

proto文件支持继承吗_关于ES6中继承的问题 B继承A B.__proto__ = A? 的相关文章

随机推荐

  • this.$emit()的用法

    this emit 是 Vue js 中的一个方法 它可以用于子组件向父组件传递事件 使用方法如下 this emit eventName args 其中 eventName 是事件名称 args 是可选参数 表示传递给父组件的数据 举个例
  • shell脚本抽取文本文件中指定字符串的方法:sed+grep方法、awk+grep方法(必要时可以联合sed以及grep)、grep+cut方法

    在linux中经常要对一些动态的文本文件抽取指定的字符串 比如执行ps命令后想要获取指定的运行进程 如ps自己 的PID号 同一个进程每次启动的时候pid号是随机分配的 该怎么办呢 当然 可以用一些截取字符串的方法 这里介绍一下用2种方法来
  • js根据数组中对象的某个属性值进行去重

    var arr from 张三 to 河南 from 王二 to 阿里 from 王二 to 杭州 from 王二 to 山东 有如上数组 想根据数组中的对象的from属性进行去重 如果from一样的话 重复只保留一条 根据ES6属性编写函
  • Linux文件系统论述

    目录 前言 一 磁盘 1 1定义 1 2结构 1 3磁盘的寻找方式 1 4磁盘的逻辑 线性结构 1 5磁盘访问的基本单位 1 6磁盘的管理 二 Linux文件系统 2 1系统结构 2 2属性解析 2 3inode相关块的解析 2 4数据块的
  • TensorFlow

    用tensorflow实现线性回归 主要考察的是一个tf的一个实现思路 贝壳 import tensorflow as tf import numpy as np import matplotlib pyplot as plt 使用nump
  • 【网络协议详解】——BGP协议(学习笔记)

    目录 1 概述 2 BGP 发言人 3 工作原理 4 报文格式 4 1 报文首部 4 2 打开报文 4 3 更新报文 4 4 保活报文 4 5 通知报文 5 BGP 的路径属性 5 1 origin 属性 5 2 AS PATH 属性 5
  • 第四讲. 经典算法之哈希映射

    第四讲 经典算法之哈希映射 1 简介 2 从一个简单例题开始 3 哈希中的碰撞冲突 3 1 线性探测法 3 2 链地址法 3 3 再哈希法 3 4 4 哈希函数的设计 4 1 更大的哈希表 4 2 更好的哈希运算 5 最后说几句 1 简介
  • 从零开始搭建基于vue的electron项目

    从零开始搭建基于vue的electron项目 1 需求背景 最近正在为基于electron的新项目做准备 本文章将为大家演示从零开始搭建基于vue的electron项目步骤 2 解决方案 1 将Vue引入Electron项目常用的两种方案分
  • 03云计算与大数据学习之云存储

    文章目录 1 应知应会 2 认识云存储 云存储 云存储技术的两种架构 云存储的种类 云存储的应用领域 3 参考文献 1 应知应会 云存储是一个以数据存储和管理为核心的云计算系统 云存储由存储节点和控制节点两个部分组成 云存储系统的结构模型由
  • notepad++快捷键

    notepad 快捷键 https wenku baidu com view 9dec474e021ca300a6c30c22590102020640f254 html wkts 1676528962334 bdQuery notepad
  • QT QTextEdit QTextBrowser追加文本不换行

    QTextEdit QTextBrowser两个控件追加文本的接口使用方法都是一样的 以QTextBrowser为例 1 追加文本自动换行 textBrowser gt append hello textBrowser gt append
  • openssl engine 实现SM4 引擎

    openssl engine 实现SM4 引擎 一 openssl engine基本介绍 二 SM4引擎实现 1 Openssl定义好的主接口 2 定义bind函数 3 实现ciphers函数 4 定义算法结构evp cipher st 5
  • 动态规划 - 钢条切割问题

    已知钢条切割的不同长度对应的不同价格如下所示 长度i 1 2 3 4 5 6 7 8 9 10 价格pi 1 5 8 9 10 17 17 20 24 30 求输入长度 输出最佳的收益 详细理论知识见 算法导论第十五章 P359 书中给出三
  • maven 通过profiles管理不同环境的依赖和插件

    Profile能让你为一个特殊的环境自定义一个特殊的构建 profile使得不同环境间构建的可移植性成为可能 Maven中的profile是一组可选的配置 可以用来设置或者覆盖配置默认值 有了profile 你就可以为不同的环境定制构建 p
  • 基于SSM的客户管理系统的设计与实现

    项目描述 该项目采用了SSM作为后端开发框架 系统中分为管理员 客户经理 销售主管 和高管四种用户角色 在项目中实现了营销管理 服务管理 统计报表 基础数据管理以及 系统管理等功能模块 下载地址 http www hrxxkj com we
  • 【C语言】辗转相除法+更相减损术+秦九韶算法

    一 辗转相除法 1 简介 辗转相除法又叫欧几里得算法 假如需要求 1997 和 615 两个正整数的最大公约数 用欧几里得算法 是这样进行的 1997 615 3 余 152 615 152 4 余7 152 7 21 余5 7 5 1 余
  • JackSon的用法详解

    JackSon的用法详解 JackSon的用法详解
  • chisel测试指令

    第一步 chisel 转换成firrtl类型 sbt test only 包名 测试类名 第二步 firrtl转换成verilog 指向verilator TESTER BACKENDS verilator sbt test only 包名
  • VMware vSphere基础命令大全

    VMware vSphere是VMware公司的虚拟化平台 包括ESXi hypervisor和vCenter Server两大组件 作为vSphere平台的管理员 掌握常用的vSphere管理命令是必要的 这些命令主要在vSphere C
  • proto文件支持继承吗_关于ES6中继承的问题 B继承A B.__proto__ = A?

    B proto proto 确实是 Function prototype 但首先它的原型是 A 其原型的原型才是函数原型 因为定义在 A 上的静态方法 B 也要继承 更新 每一个对象都有原型 但是对象的原型并不一定是对象的构造函数的 pro