深入了解原型与原型链

news2024/11/15 14:03:14

1、[[Prototype]]

JS中的对象有一个特殊的 [[Prototype]] 内置属性,其实就是对于其他对象的引用。几乎所有的对象在创建时 [[Prototype]] 属性都会被赋予一个非空的值。

var anotherObject = {
	a:2
};
// 创建一个关联到 anotherObject 的对象
var myObject = Object.create( anotherObject );
myObject.a; // 2

Object.create(…) 的原理,现在只需要知道它会创建一个对象并把这个对象的 [[Prototype]] 关联到指定的对象。

myObject 对象的 [[Prototype]] 关联到了 anotherObject。显然 myObject.a 并不存在,但是尽管如此,属性访问仍然成功地(在 anotherObject 中)找到了值 2。

使用 for…in 遍历对象时原理和查找 [[Prototype]] 链类似,任何可以通过原型链访问到(并且是 enumerable)的属性都会被枚举。使用 in 操作符来检查属性在对象中是否存在时,同样会查找对象的整条原型链(无论属性是否可枚举)

所有普通的 [[Prototype]] 链最终都会指向内置的 Object.prototype。由于所有的“普通”(内置,不是特定主机的扩展)对象都“源于”(或者说把 [[Prototype]] 链的顶端设置为)这个 Object.prototype 对象,所以它包含 JavaScript 中许多通用的功能。
比 如 说 .toString()、.valueOf()以及.hasOwnProperty(…)。稍后我们还会介绍 .isPrototypeOf(…)

1.1、属性设置和屏蔽

myObject.foo = "bar"

如果 myObject 对象中包含名为 foo 的普通数据访问属性,这条赋值语句只会修改已有的属性值。
如果 foo 不是直接存在于 myObject 中,[[Prototype]] 链就会被遍历,类似 [[Get]] 操作。
如果原型链上找不到 foo,foo 就会被直接添加到 myObject 上。
然而,如果 foo 存在于原型链上层,赋值语句 myObject.foo = “bar” 的行为就会有些不同(而且可能很出人意料)。
如 果 属 性 名 foo 既 出 现 在 myObject 中 也 出 现 在 myObject 的 [[Prototype]] 链 上 层, 那么就会发生屏蔽。myObject 中包含的 foo 属性会屏蔽原型链上层的所有 foo 属性,因为myObject.foo 总是会选择原型链中最底层的 foo 属性。

foo不直接存在于myObject中而是存在于原型链上层时myObject.foo = "bar"会出现三种情况

  1. 如果在 [[Prototype]] 链上层存在名为 foo 的普通数据访问属性并且没有被标记为只读(writable:false),那就会直接在 myObject 中添加一个名为 foo 的新属性,它是屏蔽属性。
  2. 如果在 [[Prototype]] 链上层存在 foo,但是它被标记为只读(writable:false),那么无法修改已有属性或者在 myObject 上创建屏蔽属性。这个限制只存在于 = 赋值中,使用 Object.defineProperty(…) 并不会受到影响
  3. 如果在 [[Prototype]] 链上层存在 foo 并且它是一个 setter,那就一定会调用这个 setter。foo 不会被添加到(或者说屏蔽于)myObject,也不会重新定义 foo 这个 setter。

我们应尽量少使用属性屏蔽,有些情况下会隐式产生屏蔽,看以下代码

var anotherObject = {
	a:2
};
var myObject = Object.create( anotherObject );
anotherObject.a; // 2
myObject.a; // 2
anotherObject.hasOwnProperty( "a" ); // true
myObject.hasOwnProperty( "a" ); // false
myObject.a++; // 隐式屏蔽!
anotherObject.a; // 2
myObject.a; // 3
myObject.hasOwnProperty( "a" ); // true

尽管 myObject.a++ 看起来应该(通过委托)查找并增加 anotherObject.a 属性,但是别忘了 ++ 操作相当于 myObject.a = myObject.a + 1。因此 ++ 操作首先会通过 [[Prototype]]查找属性 a 并从 anotherObject.a 获取当前属性值 2,然后给这个值加 1,接着用 [[Put]]将值 3 赋给 myObject 中新建的屏蔽属性 a。如果想让anotherObject.a 的 值 增 加,唯一的办法是anotherObject.a++。

2、“类’‘

JS和面向类的语言不同,它并没有类来作为对象的抽象模式或者说蓝图。JS中只有对象。实际上,JS才是真正应该被称为“面向对象”的语言,因为它是少有的可以不通过类,直接创建对象的语言。在 JavaScript 中,类无法描述对象的行,(因为根本就不存在类!)对象直接定义自己的行为。再说一遍,JavaScript 中只有对象

2.1、“类”函数

JS中并没有类这个概念,但是JS一直在进行模仿类,这种模仿行为实际上运用了函数的一种特殊特性:所有的函数默认都会拥有一个名为prototype的共有并且不可枚举的属性,它会指向另一个对象,这个对象通常被称为Foo的原型。

那么这个对象到底是什么呢?最直接的解释就是,通过new Foo()创建的每个对象将最终被[Prototype]链接到这个Foo.Prototype对象

在面向类的语言中,类可以被复制多次,就像使用模具制作东西一样。但是在JS中并没有类的复制机制,你不能创建一个类的多个实例,只能创建多个对象,它们[Prototype]关联的是用同一个对象。new Foo()会生成一个对象,这个新对象的内部链接[[Prototype]]关联的是foo.Prototype对象。但是实际上,new Foo()函数调用实际上并内有直接创建关联,这个关联只是一个意外的副作用。new Foo()只是间接完成了我们的目标:一个关联到其他对象的新对象,Object.create(…)方法可以更直接的做到这个

在JS中,我们并不会将一个对象(“类”)复制到另一个对象(“实例”),只是将他们关联起来

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个机制通常被称为原型继承,但是这违背了动态脚本中对应的语义。继承意味着复制操作,但是JS并不会复制对象属性,JS会在两个对象之间创建一个关联,这样一个对象就可以通过委托访问玲一个对象的属性和函数。委托可以更加准确的描述JS中对象的关联机制

2.2、“构造函数”

看以下代码

function Foo(){
	...
}
var a = new Foo()

到底是什么原因让给我们觉得Foo是一个类呢?其中一个原因是因为我们看到了new关键字,在面向类的语言中构造类实例时也会用到它。另一个原因是,看起来我们执行了类的构造函数方法,Foo()的调用方式很像初始化类时类构造函数的调用方式

function Foo(){
	...
}
Foo.prototype.constructor === Foo // true
var a = new Foo()
a.constructor === Foo // true

可以看出Foo.prototype默认有一个公有并且不可枚举的属性.constructor,这个属性引用的是对象关联的函数(即Foo)

此外,可以看到通过构造函数调用new Foo()创建的对象也有一个.constructor属性,指向“创建这个对象的函数”

但是注意,实际上 a 本身并没有 .constructor 属性。而且,虽然 a.constructor 确实指向 Foo 函数,但是这个属性并不是表示 a 由Foo“构造”

简单来说,如果没有手动修改原型链,大部分情况下.constructor属性会指向对象创建时的构造函数

上一段代码很容易让人认为 Foo 是一个构造函数,因为我们使用 new 来调用它并且看到它“构造”了一个对象。实际上,Foo 和你程序中的其他函数没有任何区别。函数本身并不是构造函数,然而,当你在普通的函数调用前面加上 new 关键字之后,就会把这个函数调用变成一个“构造函数调用”。实际上,new 会劫持所有普通函数并用构造对象的形式来调用它。

比如说:

function NothingSpecial() {
	console.log( "Don't mind me!" );
}
var a = new NothingSpecial();
// "Don't mind me!"
a; // {}

NothingSpecial 只是一个普通的函数,但是使用 new 调用时,它就会构造一个对象并赋值给 a,这看起来像是 new 的一个副作用(无论如何都会构造一个对象)。这个调用是一个构造函数调用,但是 NothingSpecial 本身并不是一个构造函数。

换句话说,在 JavaScript 中对于“构造函数”最准确的解释是,所有带 new 的函数调用。函数不是构造函数,但是当且仅当使用 new 时,函数调用会变成“构造函数调用”。

2.3、技术

function Foo(name) {
	this.name = name;
}
Foo.prototype.myName = function() {
	return this.name;
};
var a = new Foo( "a" );
var b = new Foo( "b" );
a.myName(); // "a"
b.myName(); // "b"

在这段代码中,看起来似乎创建 a 和 b 时会把 Foo.prototype 对象复制到这两个对象中,然而事实并不是这样。

在创建的过程中,a 和 b 的内部 [[Prototype]] 都会关联到 Foo.prototype 上。当 a和 b 中无法找到 myName 时,它会(通过委托)在 Foo.prototype 上找到。

实际上,对象的 .constructor 会默认指向一个函数,这个函数可以通过对象的 .prototype引用。

.constructor 并不是一个不可变属性。它是不可枚举(参见上面的代码)的,但是它的值是可写的(可以被修改)。此外,你可以给任意 [[Prototype]] 链中的任意对象添加一个名为 constructor 的属性或者对其进行修改,你可以任意对其赋值。

这句话指的是在 JavaScript 中,对象通常拥有一个 .constructor 属性,它默认指向一个函数。这个函数可以通过对象的 .prototype 属性来引用。

当你使用构造函数创建对象时,JavaScript 在创建对象的同时,会给这个对象添加一个特殊的属性 .constructor,用来指向创建该对象的构造函数。

举个例子:

function Car(make, model) {
  this.make = make;
  this.model = model;
}

let myCar = new Car('Toyota', 'Corolla');
console.log(myCar.constructor); // 输出:[Function: Car]

在这个例子中,myCar 对象的 .constructor 属性指向了 Car 这个构造函数。

另外,.constructor 属性也可以通过对象的 .prototype 属性来访问构造函数。JavaScript 中的每个函数都有一个 .prototype 属性,它是一个对象,包含了一个 constructor 属性,指向该函数自身。

例如:

function Animal(name) {
  this.name = name;
}

console.log(Animal.prototype.constructor); // 输出:[Function: Animal]

在这里,Animal.prototype.constructor 会返回 Animal 这个构造函数,因为 Animal.prototype 是一个对象,它包含了 constructor 属性,指向了 Animal 函数本身。

所以,.constructor 属性可以帮助你追踪对象是通过哪个构造函数创建的,并且通过对象的 .prototype.constructor 可以直接访问到该构造函数。

3、(原型)继承

请添加图片描述
图中由下到上的箭头表明这是委托关联,不是复制操作

function Foo(name) {
	this.name = name;
}
Foo.prototype.myName = function() {
	return this.name;
};
function Bar(name,label) {
	Foo.call( this, name );
	this.label = label;
}
// 我们创建了一个新的 Bar.prototype 对象并关联到 Foo.prototype
Bar.prototype = Object.create( Foo.prototype );
// 注意!现在没有 Bar.prototype.constructor 了
// 如果你需要这个属性的话可能需要手动修复一下它
Bar.prototype.myLabel = function() {
	return this.label;
};
var a = new Bar( "a", "obj a" );
a.myName(); // "a"
a.myLabel(); // "obj a"

这段代码的核心部分就是语句 Bar.prototype = Object.create( Foo.prototype )。调用Object.create(…) 会凭空创建一个“新”对象并把新对象内部的 [[Prototype]] 关联到你指定的对象(本例中是 Foo.prototype)。换句话说,这条语句的意思是:“创建一个新的 Bar.prototype 对象并把它关联到 Foo.prototype”。

要创建一个合适的关联对象,我们必须使用 Object.create(…) 而不是使用具有副作用的 Foo(…)。

我们来对比一下两种把 Bar.prototype 关联到 Foo.prototype 的方法:
ES6 之前需要抛弃默认的 Bar.prototype
Bar.ptototype = Object.create( Foo.prototype );
ES6 开始可以直接修改现有的 Bar.prototype
Object.setPrototypeOf( Bar.prototype, Foo.prototype );
如果忽略掉 Object.create(…) 方法带来的轻微性能损失(抛弃的对象需要进行垃圾回收),它实际上比 ES6 及其之后的方法更短而且可读性更高。不过无论如何,这是两种完全不同的语法。

3.1、检查类

在JS中检查一个实例(对象)的继承祖先(委托关联)通常被称为内省(或者反射)

function Foo(){
	...
}
Foo.Prototype.blah = ...;
var a = new Foo()

我们如何通过内省找出 a 的“祖先”(委托关联)呢?第一种方法是站在“类”的角度来判断:

a instanceof Foo; // true

instanceof 操作符的左操作数是一个普通的对象,右操作数是一个函数。instanceof 回答的问题是:在 a 的整条 [[Prototype]] 链中是否有指向 Foo.prototype 的对象?
可惜,这个方法只能处理对象(a)和函数(带 .prototype 引用的 Foo)之间的关系。如果你想判断两个对象(比如 a 和 b)之间是否通过 [[Prototype]] 链关联,只用 instanceof无法实现

下面是第二种判断 [[Prototype]] 反射的方法,它更加简洁:

Foo.prototype.isPrototypeOf( a ); // true

isPrototypeOf(…) 回答的问题是:在 a 的整条 [[Prototype]] 链中是否出现过 Foo.prototype

我们只需要两个对象就可以判断它们之间的关系。举例来说:

// 非常简单:b 是否出现在 c 的 [[Prototype]] 链中?
b.isPrototypeOf( c );

4、对象关联

现在我们知道了,[[Prototype]] 机制就是存在于对象中的一个内部链接,它会引用其他对象。

通常来说,这个链接的作用是:如果在对象上没有找到需要的属性或者方法引用,引擎就会继续在 [[Prototype]] 关联的对象上进行查找。同理,如果在后者中也没有找到需要的引用就会继续查找它的 [[Prototype]],以此类推。这一系列对象的链接被称为“原型链”。

4.1、创建关联

Object.create(…) 会创建一个新对象(bar)并把它关联到我们指定的对象(foo),这样我们就可以充分发挥 [[Prototype]] 机制的威力(委托)并且避免不必要的麻烦(比如使用 new 的构造函数调用会生成 .prototype 和 .constructor 引用)

Object.create(null) 会 创 建 一 个 拥 有 空( 或 者 说 null)[[Prototype]]链接的对象,这个对象无法进行委托。由于这个对象没有原型链,所以instanceof 操作符(之前解释过)无法进行判断,因此总是会返回 false。这些特殊的空 [[Prototype]] 对象通常被称作“字典”,它们完全不会受到原型链的干扰,因此非常适合用来存储数据。

4.2、关联关系是备用

看起来对象之间的关联关系是处理“缺失”属性或者方法时的一种备用选项。这个说法有点道理,但是我认为这并不是 [[Prototype]] 的本质。

思考下面的代码:

var anotherObject = {
	cool: function() {
		console.log( "cool!" );
	}
};
var myObject = Object.create( anotherObject );
myObject.cool(); // "cool!"

由于存在 [[Prototype]] 机制,这段代码可以正常工作

但是当你给开发者设计软件时,假设要调用 myObject.cool(),如果 myObject 中不存在 cool()时这条语句也可以正常工作的话,那你的 API 设计就会变得很“神奇”,对于未来维护你软件的开发者来说这可能不太好理解。

但是你可以让你的 API 设计不那么“神奇”,同时仍然能发挥 [[Prototype]] 关联的威力:

var anotherObject = {
    cool: function() {
    	console.log( "cool!" );
    }
};
var myObject = Object.create( anotherObject );
myObject.doCool = function() {
	this.cool(); // 内部委托!
};
myObject.doCool(); // "cool!"

5、总结

如果要访问对象中并不存在的一个属性,[[Get]] 操作就会查找对象内部[[Prototype]] 关联的对象。这个关联关系实际上定义了一条“原型链”(有点像嵌套的作用域链),在查找属性时会对它进行遍历。

所有普通对象都有内置的 Object.prototype,指向原型链的顶端(比如说全局作用域),如果在原型链中找不到指定的属性就会停止。toString()、valueOf() 和其他一些通用的功能都存在于 Object.prototype 对象上,因此语言中所有的对象都可以使用它们。

关联两个对象最常用的方法是使用 new 关键词进行函数调用,在调用的 4 个步骤中会创建一个关联其他对象的新对象。

使用 new 调用函数时会把新对象的 .prototype 属性关联到“其他对象”。带 new 的函数调用通常被称为“构造函数调用”,尽管它们实际上和传统面向类语言中的类构造函数不一样。

虽然这些 JavaScript 机制和传统面向类语言中的“类初始化”和“类继承”很相似,但是 JavaScript 中的机制有一个核心区别,那就是不会进行复制,对象之间是通过内部的[[Prototype]] 链关联的。

出于各种原因,以“继承”结尾的术语(包括“原型继承”)和其他面向对象的术语都无法帮助你理解 JavaScript 的真实机制(不仅仅是限制我们的思维模式)。相比之下,“委托”是一个更合适的术语,因为对象之间的关系不是复制而是委托。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1232119.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】使用std::vector()函数实现矩阵的加、减、点乘、点除等运算

本文通过vector&#xff08;&#xff09;函数表示矩阵的形式&#xff0c;对 加、减、点乘、点除等运算进行编码和运行&#xff0c;相应结果如下文所述。 #include <iostream> #include <vector>using namespace std;// 矩阵加法 vector<vector<int>> …

数据结构【栈】

文章目录 数据结构 栈栈的概念与结构栈接口实现 数据结构 栈 栈的概念与结构 栈是是一种特殊的线性表&#xff0c;栈的规定是只在一端插入删除数据&#xff0c;插入删除的一端叫做栈顶&#xff0c;另一端叫栈底。根据上面的特性&#xff0c;栈的数据是后入先出 栈接口实现 栈接…

pytho你-opencv划痕检测

pytho你-opencv划痕检测 这次实验&#xff0c;我们将对如下图片进行划痕检测&#xff0c;其实这个比较有难度&#xff0c;因为清晰度太差了。 我们做法如下&#xff1a; &#xff08;1&#xff09;读取图像为灰度图像&#xff0c;进行自适应直方图均衡化处理&#xff0c;增强…

【python】直方图正则化详解和示例

直方图正则化&#xff08;Histogram Normalization&#xff09;是一种图像增强技术&#xff0c;目的是改变图像的直方图以改善图像的质量。具体来说&#xff0c;它通过将图像的直方图调整为指定的形状&#xff0c;以增强图像的对比度和亮度。 直方图正则化的基本步骤如下&…

linux rsyslog综合实战1

本次我们通过rsyslog服务将A节点服务器上的单个日志(Path:/var/log/245-1.log)实时同步到B节点服务器目录下(Path:/opt/rsyslog/245) 1.rsyslog架构 2.环境信息 环境信息 HostnameIpAddressOS versionModuleNotersyslog1192.168.10.245CentOS Linux release 7.9.2009 (Core)rs…

【机器学习】038_梯度消失、梯度爆炸

一、原因 神经网络梯度 假设现在有一个 层的神经网络&#xff0c;每层的输出为一个对输入作 变换的函数结果 用 来表示第 层的输出&#xff0c;那么有下列公式&#xff1a; 链式法则计算损失 关于某一层某个参数 的梯度&#xff1a; 注意到&#xff0c; 为向量&am…

工作记录---为什么双11当天不能申请退款?(有趣~)

为什么&#xff1f; 服务降级了 服务降级&#xff1a; 当服务器压力剧增的情况下&#xff0c;根据实际业务情况及流量&#xff0c;对一些服务和页面有策略的不处理或换种简单的方式处理&#xff0c;从而释放服务器资源以保证核心交易正常运作或高效运作。 分布式系统的降级…

科大讯飞 vue.js 语音听写流式实现 全网首发

组件下载 还是最近的需求&#xff0c;页面表单输入元素过多&#xff0c;需要实现语音识别来由用户通过朗读的方式向表单中填写数据&#xff0c;尽量快的、高效的完成表单数据采集及输入。 国内科大讯飞在语音识别方面的建树还是有目共睹&#xff0c;于是还是选择了科大讯飞的平…

C/C++多级指针与多维数组

使用指针访问数组 指针类型的加减运算可以使指针内保存的首地址移动。 指针类型加n后。首地址向后移动 n * 步长 字节。 指针类型减n后。首地址向前移动 n * 步长 字节。 步长为指针所指向的类型所占空间大小。 例如&#xff1a; int *p (int *)100;p 1&#xff0c;结果为首…

校园报修抢修小程序系统开发 物业小区报修预约上门维修工单系统

开发的功能模块有&#xff1a; 1.报修工单提交&#xff1a;学生、教职员工等可以使用小程序提交报修请求。这通常包括选择报修的问题类型&#xff08;如水漏、电器故障、照明问题等&#xff09;&#xff0c;地点&#xff0c;报修联系人&#xff0c;联系电话等&#xff0c;并提供…

iPaaS和RPA,企业自动化应该如何选择?

全球著名的咨询调查机构Gartner在2022年初再次发布了《2022年12大技术趋势》报告。 Gartner是全球最具权威的IT研究与顾问咨询公司&#xff0c;成立于1979年&#xff0c;在界定及分析那些决定了商业进程的发展趋势与技术方面&#xff0c;它拥有二十年以上的丰富经验&#xff0c…

苹果CMS首涂第30套可装修DIY主题模板免授权版

这是一款可以装修的主题&#xff0c;类似淘宝店装修一样&#xff0c;可以针对首页、栏目页、详情页、播放页进行自定义装修&#xff0c;内置10个模块自由选择、添加、修改、删除、排序操作&#xff0c;后续升级还会增加更多实用和个性模块供选择&#xff0c;主题内包含的导航、…

自定义歌曲试听SeekBar

看到这个效果&#xff0c;可能会想到完全自定义一个控件&#xff0c;其实我们在系统Seekbar的基础上&#xff0c;将progressDrawable中progress背景设为透明后&#xff0c;叠加绘制试听状态下的进度区域即可 class PlayerSeekBar JvmOverloads constructor(context: Context,a…

广州华锐互动VRAR | VR课件内容编辑器解决院校实践教学难题

VR课件内容编辑器由VR制作公司广州华锐互动开发&#xff0c;是一款专为虚拟现实教育领域设计的应用&#xff0c;它能够将传统的教学内容转化为沉浸式的三维体验。通过这款软件&#xff0c;教师可以轻松创建和编辑各种虚拟场景、模型和动画&#xff0c;以更生动、直观的方式展示…

【亚马逊云科技产品测评】活动征文|aws云服务器 + 微服务Spring Cloud Nacos 实战

文章目录 前言一、拥有一台Aws Linux服务器1.1、选择Ubuntu版本Linux系统1.2、创建新密钥对1.3、网络设置1.4、配置成功&#xff0c;启动实例1.5、回到实例区域1.6、进入具体的实例1.7、设置安全组 二、在Mac上连接Aws云服务&#xff0c;并安装配置JDK112.1、解决离奇的错误2.2…

四川天蝶电子商务有限公司服务可靠吗?

作为当今最热门的社交媒体平台之一&#xff0c;抖音已经成为许多消费者和企业的重要销售渠道。然而&#xff0c;对于许多新手来说&#xff0c;如何在这个平台上开展电商服务却是一大难题。在这篇文章中&#xff0c;我们将探讨四川天蝶电子商务有限公司的抖音电商服务是否可靠&a…

俄罗斯方块游戏制作

创建包和文件夹 1.创建小方块类 package eluosifangkuai; import java.awt.image.BufferedImage; import java.util.Objects;/*** author xiaoZhao* date 2022/5/7* describe* 小方块类* 方法&#xff1a; 左移、右移、下落*/ public class Cell {// 行private int row;//…

基于野狗算法优化概率神经网络PNN的分类预测 - 附代码

基于野狗算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于野狗算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于野狗优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…

IPO解读丨高处不胜寒,澜沧古茶低头取暖?

自A股注册制改革不断深化并全面落地后&#xff0c;不少意欲登陆资本市场的企业转战港股。这个过程中&#xff0c;诞生了很多以“港股”为前缀的“第一股”——“白酒第一股”珍酒李渡、“水果零售第一股”百果园、“智能驾驶第一股”知行汽车、“运动科技第一股”Keep…… 由A…

以“防方视角”观Shiro反序列化漏洞

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 案例概述02 攻击路径03 防方思路 01 案例概述 这篇文章来自微信公众号“潇湘信安”&#xff0c;记录的某师傅如何发现、利用Shiro反序列化漏洞&#xff0c;又是怎样绕过火绒安全防护实现文件落地、…