原型与继承
原型与继承
在 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标签结合来切换不同组件。 下面给出一个示例: <!DOCTYPE html> <html><head><title>Vue 动态组件</title><scri…...
MongoDB升级经历(4.0.23至5.0.19)
MongoDB从4.0.23至5.0.19升级经历 引子:为了解决MongoDB的两个漏洞决定把MongoDB升级至最新版本,期间也踩了不少坑,在这里分享出来供大家学习与避坑~ 1、MongoDB的两个漏洞 漏洞1:MongoDB Server 安全漏洞(CVE-2021-20330) 漏洞2…...
iPhone上的个人热点丢失了怎么办?如何修复iPhone上不见的个人热点?
个人热点功能可将我们的iPhone手机转变为 Wi-Fi 热点,有了Wi-Fi 热点后就可以与附近的其他设备共享其互联网连接。 一般情况下,个人热点打开就可以使用,但也有部分用户在升级系统或越狱后发现 iPhone 的个人热点消失了。 iPhone上的个人热点…...
AI 媒人:为什么图形神经网络比 MLP 更好?
一、说明 G拉夫神经网络(GNN)!想象他们是人工智能世界的媒人,通过探索他们的联系,不知疲倦地帮助数据点找到朋友和人气。数字派对上的终极僚机。 现在,为什么这些GNN如此重要,你问?好…...
信息学奥赛一本通 1984:【19CSPJ普及组】纪念品 | 洛谷 P5662 [CSP-J2019] 纪念品
【题目链接】 ybt 1984:【19CSPJ普及组】纪念品 洛谷 P5662 [CSP-J2019] 纪念品 【题目考点】 1. 动态规划:完全背包 【解题思路】 由于小伟每天都可以买卖物品无限次,我们可以假想每天开始时,他把所有的商品都卖出ÿ…...
JVM——JVM参数指南
文章目录 1.概述2.堆内存相关2.1.显式指定堆内存–Xms和-Xmx2.2.显式新生代内存(Young Ceneration)2.3.显示指定永久代/元空间的大小 3.垃圾收集相关3.1.垃圾回收器3.2.GC记录 1.概述 在本篇文章中,你将掌握最常用的 JVM 参数配置。如果对于下面提到了一些概念比如…...
马上七夕到了,用各种编程语言实现10种浪漫表白方式
目录 1. 直接表白:2. 七夕节表白:3. 猜心游戏:4. 浪漫诗句:5. 爱的方程式:6. 爱心Python:7. 心形图案JavaScript 代码:8. 心形并显示表白信息HTML 页面:9. Java七夕快乐:…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...
高端性能封装正在突破性能壁垒,其芯片集成技术助力人工智能革命。
2024 年,高端封装市场规模为 80 亿美元,预计到 2030 年将超过 280 亿美元,2024-2030 年复合年增长率为 23%。 细分到各个终端市场,最大的高端性能封装市场是“电信和基础设施”,2024 年该市场创造了超过 67% 的收入。…...
Redis上篇--知识点总结
Redis上篇–解析 本文大部分知识整理自网上,在正文结束后都会附上参考地址。如果想要深入或者详细学习可以通过文末链接跳转学习。 1. 基本介绍 Redis 是一个开源的、高性能的 内存键值数据库,Redis 的键值对中的 key 就是字符串对象,而 val…...
