当前位置: 首页 > 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;…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...