惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
Security Archives - TechRepublic
Security Archives - TechRepublic
T
Threat Research - Cisco Blogs
A
Arctic Wolf
S
Securelist
O
OpenAI News
T
Threatpost
Forbes - Security
Forbes - Security
N
News and Events Feed by Topic
S
Secure Thoughts
H
Heimdal Security Blog
S
Security Affairs
P
Privacy International News Feed
C
Cisco Blogs
C
CERT Recently Published Vulnerability Notes
Cyberwarzone
Cyberwarzone
N
News and Events Feed by Topic
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Palo Alto Networks Blog
S
Security @ Cisco Blogs
Hacker News - Newest:
Hacker News - Newest: "LLM"
博客园 - 三生石上(FineUI控件)
月光博客
月光博客
T
Tailwind CSS Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hacker News: Ask HN
Hacker News: Ask HN
T
Troy Hunt's Blog
S
SegmentFault 最新的问题
腾讯CDC
V
Visual Studio Blog
Last Week in AI
Last Week in AI
H
Hacker News: Front Page
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Project Zero
Project Zero
WordPress大学
WordPress大学
NISL@THU
NISL@THU
博客园 - 【当耐特】
博客园 - Franky
Webroot Blog
Webroot Blog
博客园_首页
T
Tenable Blog
雷峰网
雷峰网
Google Online Security Blog
Google Online Security Blog
阮一峰的网络日志
阮一峰的网络日志
V2EX - 技术
V2EX - 技术
Recent Commits to openclaw:main
Recent Commits to openclaw:main
L
Lohrmann on Cybersecurity
The Hacker News
The Hacker News

博客园 - lzhdim

1分钟查清局域网所有IP 20260714 - 个人小作品更新 WorkBuddy 完整教程手册 专为AI而生的企业级QLC SSD!长江存储PE501 61.44TB评测:超过1PB的写入测试 32GB显存才是第一生产力!英特尔锐炫 Pro B70评测:中小企业AI降本神器 JavaScript中的this关键字 C#开发的PopoSaver泡泡屏保应用 - 开源研究系列文章 - 个人小作品 6天不间断测试告诉你到底有多省电!米家空调巨省电大1.5匹评测:制冷峰值功率不超过500W 三倍双摄加持 + D-Log 2 曲线!大疆DJI OSMO Pocket 4P全面评测:补齐短板,化身口袋电影机 晶栈4.0闪存立威!长江存储致态TiPro9000 2TB SSD评测:缓外写入超4GB/s独一档 C# 多线程同步机制详解:原理、使用与性能对比 JavaScript作用域与闭包讲解 最受欢迎的 10 大免费 AI 工具 六种AI生意,从月入一万到月入十万 5个国产大模型实测对比2026:DeepSeek、Kimi、豆包、通义、智谱哪个好用 豆包、元宝、千问、Kimi、DeepSeek,这么多AI软件,到底该用哪个? 微软免费开源了一个 Linux 操作系统,没错!是微软出品 一次看懂5种咖啡冲煮方式:意式、手冲、法压、冷萃、摩卡壶到底有什么区别 120个 实用CSS 技巧汇总合集 JavaScript运算符与表达式详解 C#开发的ScreenSaver屏保应用 - 开源研究系列文章 - 个人小作品 WinForm 中跨线程操作 UI 的解决方案 JavaScript变量与数据类型详解 苹果良心!iOS 27适配设备公布:30款机型 7年前的iPhone 11还能升级 C++图形用户界面开发入门 10个不该免费的GitHub神级项目 JavaScript语言全面概述:从历史到现代实践 一张图看懂常见咖啡 C盘空间多出来4GB:谷歌服软 Chrome本地AI大模型可禁用、删除了 96GB显存运行230B大模型!七彩虹灵创K16笔记本评测:160W性能释放 AMD锐龙AI Max+ 395加持全能移动AI工作站 AI PC最强存储搭档!雷克沙NM1090 PRO 8TB固态评测:14400MB/s满速不缩水 C#已经不是当年的C#了——我用它写了个微秒级数据库引擎 EasyTool:轻量全能的 .NET 工具类库 SQL 入门 17:MySQL 数据类型:从字符串到 JSON 的全面解析 SQL 入门 16:SQL 事务隔离级别与死锁解析(易懂) 原相3955XM+TL3228主控!小米电竞鼠标2全面评测:原生双8K究竟有多强 PCIe 4.0火力全开:闪迪奥丁马仕GX 7100 NVMe SSD上手 超乎预料的千元级电竞主板!七彩虹iGame B850M Ultra-OC V14主板评测 SQL 入门 15:SQL 事务:从 ACID 到四种常见的并发问题 名人 - 我的闪存 C#性能优化技巧 SQL 入门 14:SQL 触发器与事件:自动化数据处理 38个实用的JavaScript 技巧 一款基于 .Net WinForm 开发的节点编辑器,纯 GDI 实现,体积仅 100+Kb Masuit.Tools:这个 C# 工具库 SQL 入门 13:SQL 存储过程与函数:封装逻辑与参数处理 49个 JavaScript 代码快捷技巧,让你在 2026 年成为代码高手 20260503 - 个人小作品更新 SQL 入门 12:SQL 视图:创建、修改与可更新视图 C#如何实现Windows系统桌面截图功能... 6999元AMD新旗舰首测!锐龙9 9950X3D2性能解禁:这颗U根本不是给游戏玩家造的 SQL 入门 11:日期时间格式化、IF、CASE的使用 基于C#的校时类库的实现及使用 - 开源项目研究文章 39g无打孔+原生双8K!雷柏VT0 Air MAX / VT3s Air MAX鼠标评测:轻到飞起还快到极致 WinForm 中控件自适应窗体变化 20260413 - 个人小作品更新 SQL 入门 10:SQL 内置函数:数值、字符串与时间处理 最强麒麟芯+自研风冷 华为Mate80 Pro MAX 风驰版全面评测:涡轮散热封神 性能稳到骨子里 WiFi8核心技术特性与性能分析 2026年最新AMD/Intel桌面CPU排名:多线程、单线程、游戏性能谁才是第一 用DG对C盘进行扩容 - 初学者系列 - 学习者系列 还有比它更强的OEM固态吗!长江存储PC550 1TB评测:不用散热片也能满速的PCIe 5.0 SSD SharpCompress:跨平台的 C# 压缩与解压库 SQL 入门 9:SQL 高级子查询:ANY、EXISTS 与多位置应用 盘点接私活20个最实用的 .NET 开源项目 C#中加载图片的资源释放 20260404 - 个人小作品更新 开启iphone的墙纸玻璃效果 可能是综合性能最强的PCIe 5.0 SSD!铠侠EXCERIA PRO G2 2TB评测:AIDA64线性写入全程不掉速 SQL 入门 8:SQL 复杂查询:子查询与ALL关键词 性能最强的锐龙AI 9 H 465轻薄本!华硕无畏Pro16锐龙版2026评测 4盘RAID 0读写超1100MB/s!希捷酷狼Pro 32TB硬盘评测:百万文件快速完成备份 项目(Project)、项目集(Program)、项目组合(Portfolio) SQL 入门 7:SQL 聚合与分组:函数、GROUP BY 与 ROLLUP
JavaScript 中的原型与继承
lzhdim · 2026-07-16 · via 博客园 - lzhdim

一、从对象说起, 一切皆对象在 JS 中, 几乎所有的东西都是对象, 或者说最终都会指向某个对象. 比如:

let arr = [1, 2, 3];console.log(typeof arr); 
function foo() {}console.log(typeof foo); 

简单的对象创建: 

let person = {    name: '张三',    age: 25,    sayHi: function() {        console.log('你好,我是' + this.name);    }};
person.sayHi(); // 你好, 我是张三

但这样有个问题——每次创建新对象都要写一遍所有属性和方法, 太麻烦了! 于是我们有了后面的构造函数. 二、构造函数,对象的工厂

function Person(name, age) {    this.name = name;    this.age = age;    this.sayHi = function() {        console.log('你好, 我是' + this.name);    };}
let person1 = new Person('张三', 25);let person2 = new Person('李四', 30);
person1.sayHi(); // 你好, 我是张三person2.sayHi(); // 你好, 我是李四

这里有几个关键点: 

1. 函数名通常大写开头,这是约定俗成的构造函数命名方式

2. 使用 new 关键字调用

3. 函数内部使用 this 来指代新创建的对象

当你使用 new 调用函数时,背后发生了这些事: 

1. 创建一个全新的空对象

2. 将这个空对象的 __proto__ 指向构造函数的 prototype 属性

3. 将构造函数中的 this 绑定到这个新对象

4. 执行构造函数中的代码

5. 如果构造函数没有显式返回对象,则返回这个新对象

三、原型登场

上面的构造函数方式有个问题——每个实例都会创建自己的方法副本, 浪费内存, 这时候,原型(prototype)就派上用场了!

什么是原型?

每个函数都有一个 prototype 属性, 它指向一个对象. 当使用这个函数作为构造函数创建实例时, 所有实例都会共享这个原型对象上的属性和方法.

改进版的 Person: 

function Person(name, age) {    this.name = name;    this.age = age;}
// 将方法放在原型上Person.prototype.sayHi = function() {    console.log('你好,我是' + this.name);};
let person1 = new Person('张三'25);let person2 = new Person('李四'30);
console.log(person1.sayHi === person2.sayHi); 

什么是原型链?

当我们访问一个对象的属性时, JavaScript 会:

1. 先在对象自身属性中查找

2. 如果没找到, 就去对象的 __proto__ (即构造函数的 prototype) 中查找

3. 如果还没找到, 就继续往 __proto__.__proto__ 中查找

4. 直到找到 Object.prototype (最顶层的原型,它的 __proto__ 是 null)

这就是原型链, JavaScript的继承机制.

function Person() {}Person.prototype.species = '人类';
let p = new Person();console.log(p.species); //"人类" - 从原型上找到的console.log(p.__proto__ === Person.prototype); console.log(Person.prototype.__proto__ === Object.prototype); console.log(Object.prototype.__proto__); 

如果对象自身有属性, 就不会去原型上找了:

p.species = '地球人';console.log(p.species); //"地球人" - 自身的属性console.log(Person.prototype.species); 
delete p.species;console.log(p.species); //"人类" - 删除自身属性后又从原型上找到了

四、几种继承的方式

1)原型链继承: 

function Parent() {    this.parentProp = '父类属性';}Parent.prototype.parentMethod = function() {    console.log('父类方法');};
function Child() {    this.childProp = '子类属性';}
// 关键点: 子类的原型指向父类的实例Child.prototype = new Parent();
let child = new Child();console.log(child.childProp); // "子类属性"console.log(child.parentProp); // "父类属性"-通过原型链找到的child.parentMethod(); // "父类方法"

问题: 

  1. 所有子类实例共享同一个父类实例的属性(如果是引用类型就麻烦了)

  2. 创建子类实例时无法向父类构造函数传参

2)构造函数继承: 

function Parent(name) {    this.name = name;    this.colors = ['red', 'blue'];}
function Child(name, age) {    Parent.call(this, name); //关键点:在子类构造函数中调用父类构造函数    this.age = age;}
let child1 = new Child('张三', 25);child1.colors.push('green');
let child2 = new Child('李四', 30);console.log(child2.colors); //["red", "blue"]-不受child1影响

优点: 

1. 避免了引用类型属性被所有实例共享

2. 可以在子类中向父类传参

缺点: 

  1. 方法都在构造函数中定义,每次创建实例都会创建一遍方法

  2. 不能继承父类原型上的方法

3)组合继承:

结合原型链继承和构造函数继承的优点:

function Parent(name) {    this.name = name;    this.colors = ['red', 'blue'];}Parent.prototype.sayName = function() {    console.log(this.name);};
function Child(name, age) {    Parent.call(this, name); //第二次调用Parent    this.age = age;}
Child.prototype = new Parent(); Child.prototype.constructor = Child; Child.prototype.sayAge = function() {    console.log(this.age);};
let child1 = new Child('张三', 25);child1.colors.push('green');child1.sayName(); //"张三"child1.sayAge(); //25
let child2 = new Child('李四', 30);console.log(child2.colors); //["red", "blue"]

4)寄生组合继承:

function inheritPrototype(child, parent) {    let prototype = Object.create(parent.prototype);     //Object.create 是创建以指定对象为原型的新对象的方法    prototype.constructor = child; // 修复constructor    child.prototype = prototype; // 将副本作为子类的原型}
function Parent(name) {    this.name = name;    this.colors = ['red', 'blue'];}Parent.prototype.sayName = function() {    console.log(this.name);};
function Child(name, age) {    Parent.call(this, name);    this.age = age;}
// 关键: 使用我们封装的inheritPrototype函数inheritPrototype(Child, Parent);
Child.prototype.sayAge = function() {    console.log(this.age);};
let child = new Child('张三', 25);child.sayName(); // "张三"child.sayAge(); // 25

优点:

1. 只调用一次父类构造函数

2. 子类原型上不会有多余的父类属性

3. 原型链保持不变

五、ES6的class

ES6 引入了 class 语法, 让面向对象编程更加直观:

class Parent {    constructor(name) {        this.name = name;        this.colors = ['red''blue'];    }
    sayName() {        console.log(this.name);    }}
class Child extends Parent {    constructor(name, age) {        super(name); // 必须在使用this之前调用super        this.age = age;    }
    sayAge() {        console.log(this.age);    }}
let child = new Child('张三'25);child.sayName(); // "张三"child.sayAge(); // 25

class 本质上仍然是基于原型的语法糖. 上面的代码大致相当于:

function Parent(name) {    this.name = name;    this.colors = ['red''blue'];}
Parent.prototype.sayName = function() {    console.log(this.name);};
function Child(name, age) {    Parent.call(this, name);    this.age = age;}
Child.prototype = Object.create(Parent.prototype);Child.prototype.constructor = Child;
Child.prototype.sayAge = function() {    console.log(this.age);};

class 还提供了静态方法和属性的简洁写法: 

class MyClass {    static staticMethod() {        console.log('我是静态方法');    }
    static staticProperty = '我是静态属性';}
MyClass.staticMethod(); //"我是静态方法"console.log(MyClass.staticProperty); 

六、其他相关内容

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上.

function myInstanceof(instance, constructor) {    let proto = Object.getPrototypeOf(instance);    while (proto) {        if (proto === constructor.prototype) {            return true;        }        proto = Object.getPrototypeOf(proto);    }    return false;}
console.log([] instanceof Array); console.log(myInstanceof([], Array)); 

原型可以被修改, 这可能导致安全问题: 

// 不要这样做!Object.prototype.hack = function() {    console.log('被黑了!');};
let obj = {};obj.hack(); // "被黑了!"