当前位置: 首页 > news >正文

原型与继承

原型与继承

在 JavaScript 中,对象有一个特殊的隐藏属性 [[Prototype]](如规范中所命名的),它要么为 null,要么就是对另一个对象的引用。该对象被称为“原型。

当我们从 object 中读取一个缺失的属性时,JavaScript 会自动从原型中获取该属性。在编程中,这被称为“原型继承”。

'use strict';const user = {name: 'user',age: 18
}
const admin = {__proto__: user,  // __proto__ 的值可以是对象,也可以是 null。而其他的类型都会被忽略。一个对象只能有一个 [[Prototype]]。一个对象不能从其他两个对象获得继承。name: 'admin',
}
console.log(admin.name);   // admin
console.log(admin.age);  // 18console.log(admin.__proto__);  // { name: 'user', age: 18 }
console.log(admin.__proto__.__proto__);  // [Object: null prototype] {}
console.log(admin.__proto__.__proto__.__proto__);  // null
// 获取对象所有的属性名, 包括不可迭代的属性
console.log(Object.getOwnPropertyNames(admin.__proto__.__proto__));
/* 
['constructor','__defineGetter__','__defineSetter__','hasOwnProperty','__lookupGetter__','__lookupSetter__','isPrototypeOf','propertyIsEnumerable','toString','valueOf','__proto__','toLocaleString'
]
*/
// 只返回自己的 key
console.log(Object.keys(admin));  // [ 'name' ]
// for..in 会遍历自己以及继承的键
for(let key in admin) console.log(key);  // name age
// 方法 obj.hasOwnProperty(key):如果 obj 具有自己的(非继承的)名为 key 的属性,则返回 true。
console.log(admin.hasOwnProperty("name"));  // true
console.log(admin.hasOwnProperty("age"));  // false
  • __proto__[[Prototype]] 的因历史原因而留下来的 getter/setter

  • 初学者常犯一个普遍的错误,就是不知道 __proto__[[Prototype]] 的区别。

  • 请注意,__proto__ 与内部的 [[Prototype]] 不一样__proto__[[Prototype]] 的 getter/setter。稍后,我们将看到在什么情况下理解它们很重要,在建立对 JavaScript 语言的理解时,让我们牢记这一点。

  • __proto__ 属性有点过时了。它的存在是出于历史的原因,现代编程语言建议我们应该使用函数 Object.getPrototypeOf/Object.setPrototypeOf 来取代 __proto__ 去 get/set 原型。稍后我们将介绍这些函数。

  • 根据规范,__proto__ 必须仅受浏览器环境的支持。但实际上,包括服务端在内的所有环境都支持它,因此我们使用它是非常安全的。

  • 由于 __proto__ 标记在观感上更加明显,所以我们在后面的示例中将使用它。

let user = {setName(name){this.name = name}
}
let admin = {__proto__: user
}
// 即使是调用的继承对象user中的方法, 但是方法中的this依然指向调用者admin
admin.setName("admin");
console.log(admin.name);  // admin
console.log(user.name);  // undefind

我们还记得,可以使用诸如 new F() 这样的构造函数来创建一个新对象。

如果 F.prototype 是一个对象,那么 new 操作符会使用它为新对象设置 [[Prototype]]

"use strict";MyArray.prototype = new Array();   // * 与使用 ** 行, ***行 等效
// Array.prototype = Array.prototype  // **
function MyArray() {// this.__proto__ = new Array();  // ***// this 是一个new出来的具体对象, MyArray 是一个构造函数
}const arr = new MyArray();
// MyArray.prototype上的属性方法可直接使用, 未找到会自动向上寻找, 在`arr.__proto__`上找到constructor方法
console.log(arr.constructor === Array); // true
console.log(arr.__proto__.constructor === Array); // true
// 调用Array.prototype 上的方法
arr.push(...[1, 2, 3]);
console.log(arr);

每个函数都有 "prototype" 属性,即使我们没有提供它。

默认的 "prototype" 是一个只有属性 constructor 的对象,属性 constructor 指向函数自身。

"use strict";function User() {}console.log(Object.getOwnPropertyDescriptors(User.prototype));
/* {constructor: {value: [Function: User],writable: true,enumerable: false,configurable: true}} */
console.log(User.prototype.constructor === User); // true
console.log(User.prototype.__proto__.constructor === Object); // true
console.log(User.prototype.__proto__.__proto__ === null); // true, null没有构造方法const user = new User();
console.log(user.__proto__ === User.prototype); // true
console.log(user.__proto__.__proto__.__proto__ === null); // true, 原型链的尽头是null
// User.prototype 上的属性可直接使用
console.log(user.constructor === User);  // true

在常规对象上,prototype 没什么特别的:

let user = {name: "John",prototype: "Bla-bla" // 这里只是普通的属性
};

默认情况下,所有函数都有 F.prototype = {constructor:F},所以我们可以通过访问它的 "constructor" 属性来获取一个对象的构造器。

"use strict";
function User(name){this.name = name;
}
// 构造方法应加上关键字new调用
let user1 = new User("User1");
console.log(user1);let user2 = new User.prototype.constructor("User2");
console.log(user2);let user3 = new user1.__proto__.constructor("User3");
console.log(user3);let user4 = new user1.constructor("User4");
console.log(user4);  // User { name: 'User4' }User.prototype = {}
let user5 = new user1.constructor("User5");
console.log(user5);  // { name: 'User5' }  是 new Object('User5')的结果, 继续向上找constructoruser1.__proto__ = null  // user1.constructor is not a constructor, 如果给{}, 结果是 [String: 'User6']
let user6 = new user1.constructor("User6");
console.log(user6);  

内建对象的原型挂载着相关属性和方法

可向prototype上添加自定义方法或属性

// 通过原型查看数组, 字符串等相关的函数(可在浏览器环境下直接使用String.prototype)// console.log(Object.getOwnPropertyDescriptors(Array.prototype));
console.log(Object.getOwnPropertyNames(Array.prototype));
/* ['length',      'constructor',    'concat','copyWithin',  'fill',           'find','findIndex',   'lastIndexOf',    'pop','push',        'reverse',        'shift','unshift',     'slice',          'sort','splice',      'includes',       'indexOf','join',        'keys',           'entries','values',      'forEach',        'filter','flat',        'flatMap',        'map','every',       'some',           'reduce','reduceRight', 'toLocaleString', 'toString','at'
] */
// 所有函数或属性名
console.log(Object.getOwnPropertyNames(String.prototype));
/* ['length',            'constructor',   'anchor','big',               'blink',         'bold','charAt',            'charCodeAt',    'codePointAt','concat',            'endsWith',      'fontcolor','fontsize',          'fixed',         'includes','indexOf',           'italics',       'lastIndexOf','link',              'localeCompare', 'match','matchAll',          'normalize',     'padEnd','padStart',          'repeat',        'replace','replaceAll',        'search',        'slice','small',             'split',         'strike','sub',               'substr',        'substring','sup',               'startsWith',    'toString','trim',              'trimStart',     'trimLeft','trimEnd',           'trimRight',     'toLocaleLowerCase','toLocaleUpperCase', 'toLowerCase',   'toUpperCase','valueOf',           'at'
] */
console.log(Object.getOwnPropertyNames(Number.prototype));
/* ['constructor','toExponential','toFixed','toPrecision','toString','valueOf','toLocaleString'
] */
console.log(Object.getOwnPropertyNames(Boolean.prototype));
/* [ 'constructor', 'toString', 'valueOf' ] */console.log(Object.getOwnPropertyNames(Date.prototype));
/* ['constructor',        'toString',           'toDateString','toTimeString',       'toISOString',        'toUTCString','toGMTString',        'getDate',            'setDate','getDay',             'getFullYear',        'setFullYear','getHours',           'setHours',           'getMilliseconds','setMilliseconds',    'getMinutes',         'setMinutes','getMonth',           'setMonth',           'getSeconds','setSeconds',         'getTime',            'setTime','getTimezoneOffset',  'getUTCDate',         'setUTCDate','getUTCDay',          'getUTCFullYear',     'setUTCFullYear','getUTCHours',        'setUTCHours',        'getUTCMilliseconds','setUTCMilliseconds', 'getUTCMinutes',      'setUTCMinutes','getUTCMonth',        'setUTCMonth',        'getUTCSeconds','setUTCSeconds',      'valueOf',            'getYear','setYear',            'toJSON',             'toLocaleString','toLocaleDateString', 'toLocaleTimeString'
] */
console.log(Object.getOwnPropertyNames(Map.prototype));
/* ['constructor', 'get','set',         'has','delete',      'clear','entries',     'forEach','keys',        'size','values'
] */
console.log(Object.getOwnPropertyNames(WeakMap.prototype));
/* [ 'constructor', 'delete', 'get', 'set', 'has' ] */console.log(Object.getOwnPropertyNames(Function.prototype));
/* ['length',      'name','arguments',   'caller','constructor', 'apply','bind',        'call','toString'
] */
console.log(Object.getOwnPropertyNames(Object.prototype));
/* ['constructor','__defineGetter__','__defineSetter__','hasOwnProperty','__lookupGetter__','__lookupSetter__','isPrototypeOf','propertyIsEnumerable','toString','valueOf','__proto__','toLocaleString'
] */
console.log(Object.getOwnPropertyNames(Object));
/* ['length','name','prototype','assign','getOwnPropertyDescriptor','getOwnPropertyDescriptors','getOwnPropertyNames','getOwnPropertySymbols','is','preventExtensions','seal','create','defineProperties','defineProperty','freeze','getPrototypeOf','setPrototypeOf','isExtensible','isFrozen','isSealed','keys','entries','fromEntries','values','hasOwn'
] */

如果速度很重要,就请不要修改已存在的对象的 [[Prototype]]

通常我们只在创建对象的时候设置它一次,自那之后不再修改

现代的获取/设置原型的方法有:

  • Object.getPrototypeOf(obj) —— 返回对象 obj[[Prototype]]
  • Object.setPrototypeOf(obj, proto) —— 将对象 obj[[Prototype]] 设置为 proto

Object.create(null)这样的对象称为 “very plain” 或 “pure dictionary” 对象,因为它们甚至比通常的普通对象(plain object){...} 还要简单。

缺点是这样的对象没有任何内建的对象的方法,例如 toString

'use strict';
// 这个对象没有原型([[Prototype]] 是 null)
// 创建一个以null为原型的对象, 在obj中, __ptoto__、toString等原本的内建属性和方法不复存在, 只是普通的方法和属性
let obj = Object.create(null);console.log(obj.__proto__);  // undefined
// console.log(obj.toString());  // TypeError: obj.toString is not a function// 正常的
let obj1 = {};
console.log(obj1.__proto__);  // [Object: null prototype] {}
console.log(obj1.toString());  // [object Object]

相关文章:

原型与继承

原型与继承 在 JavaScript 中,对象有一个特殊的隐藏属性 [[Prototype]](如规范中所命名的),它要么为 null,要么就是对另一个对象的引用。该对象被称为“原型。 当我们从 object 中读取一个缺失的属性时,Jav…...

Flink流批一体计算(14):PyFlink Tabel API之SQL查询

举个例子 查询 source 表,同时执行计算 # 通过 Table API 创建一张表: source_table table_env.from_path("datagen") # 或者通过 SQL 查询语句创建一张表: source_table table_env.sql_query("SELECT * FROM datagen&quo…...

JRebel插件扩展-mac版

前言 上一篇分享了mac开发环境的搭建,但是欠了博友几个优化的债,今天先还一个,那就是idea里jRebel插件的扩展。 一、场景回眸 这个如果在win环境那扩展是分分钟,一个exe文件点点就行。现在在mac环境就没有这样的dmg可以执行的&…...

C语言中常见的一些语法概念和功能

常用代码: 程序入口:int main() 函数用于定义程序的入口点。 输出:使用 printf() 函数可以在控制台打印输出。 输入:使用 scanf() 函数可以接收用户的输入。 条件判断:使用 if-else 语句可以根据条件执行不同的代码…...

Python土力学与基础工程计算.PDF-钻探泥浆制备

Python 求解代码如下: 1. rho1 2.5 # 黏土密度,单位:t/m 2. rho2 1.0 # 泥浆密度,单位:t/m 3. rho3 1.0 # 水的密度,单位:t/m 4. V 1.0 # 泥浆容积,单位:…...

【机器学习】— 2 图神经网络GNN

一、说明 在本文中,我们探讨了图神经网络(GNN)在推荐系统中的潜力,强调了它们相对于传统矩阵完成方法的优势。GNN为利用图论来改进推荐系统提供了一个强大的框架。在本文中,我们将在推荐系统的背景下概述图论和图神经网…...

QT的布局与间隔器介绍

布局与间隔器 1、概述 QT中使用绝对定位的布局方式,无法适用窗口的变化,但是,也可以通过尺寸策略来进行 调整,使得 可以适用窗口变化。 布局管理器作用最主要用来在qt设计师中进行控件的排列,另外,布局管理…...

深入浅出Pytorch函数——torch.nn.Linear

分类目录:《深入浅出Pytorch函数》总目录 对输入数据做线性变换 y x A T b yxA^Tb yxATb 语法 torch.nn.Linear(in_features, out_features, biasTrue, deviceNone, dtypeNone)参数 in_features:[int] 每个输入样本的大小out_features :…...

Vue3.2+TS的defineExpose的应用

defineExpose通俗来讲,其实就是讲子组件的方法或者数据,暴露给父组件进行使用,这样对组件的封装使用,有很大的帮助,那么defineExpose应该如何使用,下面我来用一些实际的代码,带大家快速学会defi…...

牛客网Python入门103题练习|【08--元组】

⭐NP62 运动会双人项目 描述 牛客运动会上有一项双人项目,因为报名成功以后双人成员不允许被修改,因此请使用元组(tuple)进行记录。先输入两个人的名字,请输出他们报名成功以后的元组。 输入描述: 第一…...

Jenkins改造—nginx配置鉴权

先kill掉8082的端口进程 netstat -natp | grep 8082 kill 10256 1、下载nginx nginx安装 EPEL 仓库中有 Nginx 的安装包。如果你还没有安装过 EPEL,可以通过运行下面的命令来完成安装 sudo yum install epel-release 输入以下命令来安装 Nginx sudo yum inst…...

(二)VisionOS平台概述

2.VisionOS平台概述 1. VisionOS平台概述 Unity 对VisionOS的支持将 Unity 编辑器和运行时引擎的全部功能与RealityKit提供的渲染功能结合起来。Unity 的核心功能(包括脚本、物理、动画混合、AI、场景管理等)无需修改即可支持。这允许游戏和应用程序逻…...

菜单中的类似iOS中开关的样式

背景是我们有需求,做类似ios中开关的按钮。github上有一些开源项目,比如 SwitchButton, 但是这个项目中提供了很多选项,并且实际使用中会出现一些奇怪的问题。 我调整了下代码,把无关的功能都给删了,保留核…...

Vue 2 动态组件和异步组件

先阅读 【Vue 2 组件基础】中的初步了解动态组件。 动态组件与keep-alive 我们知道动态组件使用is属性和component标签结合来切换不同组件。 下面给出一个示例&#xff1a; <!DOCTYPE html> <html><head><title>Vue 动态组件</title><scri…...

MongoDB升级经历(4.0.23至5.0.19)

MongoDB从4.0.23至5.0.19升级经历 引子&#xff1a;为了解决MongoDB的两个漏洞决定把MongoDB升级至最新版本&#xff0c;期间也踩了不少坑&#xff0c;在这里分享出来供大家学习与避坑~ 1、MongoDB的两个漏洞 漏洞1&#xff1a;MongoDB Server 安全漏洞(CVE-2021-20330) 漏洞2…...

iPhone上的个人热点丢失了怎么办?如何修复iPhone上不见的个人热点?

个人热点功能可将我们的iPhone手机转变为 Wi-Fi 热点&#xff0c;有了Wi-Fi 热点后就可以与附近的其他设备共享其互联网连接。 一般情况下&#xff0c;个人热点打开就可以使用&#xff0c;但也有部分用户在升级系统或越狱后发现 iPhone 的个人热点消失了。 iPhone上的个人热点…...

AI 媒人:为什么图形神经网络比 MLP 更好?

一、说明 G拉夫神经网络&#xff08;GNN&#xff09;&#xff01;想象他们是人工智能世界的媒人&#xff0c;通过探索他们的联系&#xff0c;不知疲倦地帮助数据点找到朋友和人气。数字派对上的终极僚机。 现在&#xff0c;为什么这些GNN如此重要&#xff0c;你问&#xff1f;好…...

信息学奥赛一本通 1984:【19CSPJ普及组】纪念品 | 洛谷 P5662 [CSP-J2019] 纪念品

【题目链接】 ybt 1984&#xff1a;【19CSPJ普及组】纪念品 洛谷 P5662 [CSP-J2019] 纪念品 【题目考点】 1. 动态规划&#xff1a;完全背包 【解题思路】 由于小伟每天都可以买卖物品无限次&#xff0c;我们可以假想每天开始时&#xff0c;他把所有的商品都卖出&#xff…...

JVM——JVM参数指南

文章目录 1.概述2.堆内存相关2.1.显式指定堆内存–Xms和-Xmx2.2.显式新生代内存(Young Ceneration)2.3.显示指定永久代/元空间的大小 3.垃圾收集相关3.1.垃圾回收器3.2.GC记录 1.概述 在本篇文章中&#xff0c;你将掌握最常用的 JVM 参数配置。如果对于下面提到了一些概念比如…...

马上七夕到了,用各种编程语言实现10种浪漫表白方式

目录 1. 直接表白&#xff1a;2. 七夕节表白&#xff1a;3. 猜心游戏&#xff1a;4. 浪漫诗句&#xff1a;5. 爱的方程式&#xff1a;6. 爱心Python&#xff1a;7. 心形图案JavaScript 代码&#xff1a;8. 心形并显示表白信息HTML 页面&#xff1a;9. Java七夕快乐&#xff1a;…...

Linuxbonding链路异常定位实战

Linuxbonding链路异常定位实战这是一篇面向中级 Linux 使用者的技术文章&#xff0c;主题聚焦在bonding链路&#xff0c;重点讨论链路聚合、冗余切换和接口状态。在真实生产环境中&#xff0c;bonding链路相关问题往往不会以单一错误形式出现&#xff0c;而是混杂在日志、权限、…...

基于Arduino与TSL2561的光照度测量系统:从硬件连接到软件调试

1. 项目概述&#xff1a;从园艺需求到嵌入式光测量方案最近在折腾一个园艺相关的项目&#xff0c;需要量化评估不同覆盖材料&#xff08;比如遮阳网、塑料薄膜&#xff09;对光线透射率的影响。说白了&#xff0c;就是想精确知道&#xff0c;盖上一层材料后&#xff0c;底下还能…...

开源虚拟世界引擎Vircadia核心架构与部署实战指南

1. 项目概述&#xff1a;一个开源虚拟世界的核心引擎如果你对构建一个属于自己的、去中心化的虚拟世界感兴趣&#xff0c;那么你很可能已经听说过或者正在寻找一个合适的底层引擎。今天要聊的这个项目&#xff0c;就是这样一个领域的重量级选手&#xff1a;vircadia/vircadia-n…...

JetBrains IDE 30天试用重置:一键解决方案的完整实践指南

JetBrains IDE 30天试用重置&#xff1a;一键解决方案的完整实践指南 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter 当您正专注于代码调试时&#xff0c;IDE突然弹出"评估期已结束"的红色警告&#xf…...

从开源物理拼图游戏学习Unity 2D物理引擎与游戏架构设计

1. 项目概述与核心价值 最近在GitHub上看到一个挺有意思的项目&#xff0c;叫“openclaw-puzzle-game”。光看名字&#xff0c;你可能会觉得这又是一个普通的开源拼图游戏&#xff0c;但点进去仔细研究后&#xff0c;我发现它的设计思路和实现方式&#xff0c;对于想学习游戏开…...

告别时间混乱:一份超全的Hive日期函数使用手册与常见错误排查

告别时间混乱&#xff1a;一份超全的Hive日期函数使用手册与常见错误排查 在数据开发领域&#xff0c;时间数据处理一直是高频且易错的环节。无论是日志分析、用户行为追踪还是财务报表生成&#xff0c;准确的时间计算都是确保数据质量的基础。Hive作为大数据生态中广泛使用的数…...

LLM应用快速演示框架:从架构解析到智能体开发的实战指南

1. 项目概述&#xff1a;一个面向开发者的LLM应用快速演示框架最近在GitHub上闲逛&#xff0c;发现了一个名为wronai/llm-demo的项目&#xff0c;点进去一看&#xff0c;瞬间觉得眼前一亮。这可不是又一个简单的“Hello World”式的大语言模型调用示例&#xff0c;而是一个结构…...

OpenClaw从入门到应用——工具(Tools):多智能体沙箱与工具配置

通过OpenClaw实现副业收入&#xff1a;《OpenClaw赚钱实录&#xff1a;从“养龙虾“到可持续变现的实践指南》 概述 在多智能体设置中&#xff0c;每个智能体现在可以拥有自己的&#xff1a; 沙箱配置&#xff08;agents.list[].sandbox 会覆盖 agents.defaults.sandbox&…...

保姆级教程:INCA 7.2.3 从新建工程到观测标定的完整流程(附A2L文件处理技巧)

INCA 7.2.3 全流程实战指南&#xff1a;从工程搭建到参数标定的深度解析 在汽车电子开发领域&#xff0c;标定工具链的掌握程度直接影响开发效率。作为行业标准的INCA软件&#xff0c;其7.2.3版本在工程管理、实时观测和参数标定方面提供了更完善的解决方案。本文将采用"操…...

基于CircuitPython与NeoPixel打造可编程LED亚克力灯牌:从硬件选型到代码实现

1. 项目概述&#xff1a;打造你的专属可编程光之铭牌在创客和电子爱好者的世界里&#xff0c;总有一些项目能完美地融合软件编程的灵活性与硬件制作的实体成就感。今天要分享的&#xff0c;就是这样一个让我爱不释手的小玩意儿&#xff1a;一个基于CircuitPython和NeoPixel的可…...