【原型详解】JavaScript原型链:深入了解Prototype,超级详细!!!

在这里插入图片描述

😁 作者简介:一名大四的学生,致力学习前端开发技术
⭐️个人主页:夜宵饽饽的主页
❔ 系列专栏:JavaScript进阶指南
👐学习格言:成功不是终点,失败也并非末日,最重要的是继续前进的勇气

​🔥​前言:

有关对象中的原型和原型链,这里面有很多的知识体系,对于构造函数和所谓的原型继承到底是什么?,对于constructor的理解比较模糊,还有在javaScript中所谓的“类”和对象是什么关系?这些问题在本篇都可以了解到,请大家认真理解本篇博客,会受益匪浅的,希望可以帮助到大家,欢迎大家的补充和纠正

文章目录

  • 原型
    • 1 [[ Prototype ]]
    • 2 属性设置和屏蔽
    • 3 类
      • 3.1 “类”函数
      • 3.2 构造函数与类的误解
      • 3.3 构造函数是什么
      • 3.4 构造函数的属性是什么
      • 3.5 实例的constructor属性
      • 5.3 (原型)继承
    • 4 对象关联
      • 4.1 创建关联
      • 4.2 关联关系的意义

原型

1 [[ Prototype ]]

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

🤔 思考以下代码:

//第一种情况
var myObject={
	a:2
}

//当对象上有这个属性时
myObject.a //2

//第二种情况
var anotherObject={
    a:2
}
// 创建一个关联到 anotherObject 的对象
var myObject=Object.create(anotherObject)
//当对象上没有,对象的原型上有时
myObject.a //2

当我们引用对象属性时会触发Get操作。比如上述代码中myObject.a。

  • 第一步会检查myObject对象本身是否有这个属性,如果有就用它
  • 当myObject对象本身没有时,会进行第二步,检查myObject对象的[[Prototype链]](代码中是anotherObject对象)
  • 如果 anotherObject 中也找不到 a 并且 [[Prototype]] 链不为空的话,就会继续查找下去
  • 这个过程会持续找到匹配的属性名或者完整条[[Prototype]]链,如果后者的话,Get操作会返回undefined

2 属性设置和屏蔽

当我们给对象设置属性并不是仅仅是添加一个新属性或者修改已有的属性值

接下来,我们完整的讲解一下这个过程:

myObject.foo='bar'
  • 如果 myObject 对象中包含名为 foo 的普通数据访问属性,这条赋值语句只会修改已有的属性值
  • 如果 foo 不是直接存在于 myObject 中,[[Prototype]] 链就会被遍历,类似 Get 操作。如果原型链上找不到 foo,foo 就会被直接添加到 myObject 上。🌱 ​这种情况下,如果foo存在原型链上层,赋值语句会行为会有所不同,下面我们会仔细介绍
  • 如果属性名 foo 既出现在 myObject 中也出现在 myObject 的 [[Prototype]] 链上层,那么就会发生屏蔽。myObject 中包含的 foo 属性会屏蔽原型链上层的所有 foo 属性,因为myObject.foo 总是会选择原型链中最底层的 foo 属性

🌳 屏蔽 比我们想象中的更加复杂,下面我们分析一下如果foo不直接存在于myObject中,而是存在于原型链上层myObject.foo='bar’的三种情况

  • 如果在 [[Prototype]] 链上层存在名为 foo 的普通数据访问属性并且没有被标记为只读(writable:false),那就会直接在 myObject 中添加一个名为 foo 的新属性,它是屏蔽属性
  • 如果在 [[Prototype]] 链上层存在 foo,但是它被标记为只读(writable:false),那么无法修改已有属性或者在 myObject 上创建屏蔽属性。如果运行在严格模式下,代码会抛出一个错误。否则,这条赋值语句会被忽略。总之,不会发生屏蔽
  • 如果在 [[Prototype]] 链上层存在 foo 并且它是一个 setter,那就一定会调用这个 setter。foo 不会被添加到(或者说屏蔽于)myObject,也不会重新定义 foo 这个 setter。

📝 小贴士:如果希望在第二种和第三种情况下也屏蔽 foo,那就不能使用 = 操作符来赋值,而是使用 Object.defineProperty(…)来向 myObject 添加 foo。

❗️ 以下代码会产生隐式屏蔽,需要注意

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,接着将值 3 赋给 myObject 中新建的屏蔽属性 a

3 类

现在你可能会很好奇:为什么一个对象需要关联到另一个对象?这样做有什么好处?这个问题非常好,但是在回答之前我们首先要理解 [[Prototype]]“不是”什么。

JavaScript 和面向类的语言不同,它并没有类来作为对象的抽象模式或者说蓝图。JavaScript中只有对象

实际上,JavaScript才是真正应该被称为“面向对象”语言,因为它是少有的可以不通类,直接创建对象的语言。

在 JavaScript 中,类无法描述对象的行为,(因为根本就不存在类!)对象直接定义自己的行为。再说一遍,JavaScript 中只有对象。

3.1 “类”函数

在JavaScript中是没有类的,只有对象,所以可能会产生一种奇怪的行为,那就是 模仿类,我们会仔细分析这种方法

这种奇怪的类似类的行为利用函数的一种特殊特性:所有的函数默认都会拥有一个名为prototype的公有并且不可枚举的属性,它指向另一个对象

function Foo(){

}

Foo.prototype //{}

这个对象通常被称为Foo原型,因为我们通过名为 Foo.prototype 的属性引用来访问它。

🤔 那么,这个对象到底是什么?

🌴 这个对象是在调用new Foo()时创建的,最后会被关联到这个“Foo.prototype” 对象上

我们来验证一下:

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

Object.getProtypeOf(a)=== Foo.prototype //true

调用new Foo()时会创建a(关于this那章),其中的第二步就是给a一个内部的[[Protype]] 链接,关联到Foo.prototype指向那个对象

🤔 接下来,我们来思考一下一些问题?

  • 面向类的语言有什么独特?
  • JavaScript模仿类的行为是什么?

🌴 理解如下:

在面向类的语言中,类可以被复制(或者说实例化)多次,就像用模具制作东西一样。之所以会这样是因为实例化(或者继承)一个类就意味着“把类的行为复制到物理对象中”,对于每一个新实例来说都会重复这个过程。

但是在 JavaScript 中,并没有类似的复制机制。你不能创建一个类的多个实例,只能创建多个对象,它们 [[Prototype]] 关联的是同一个对象。但是在默认情况下并不会进行复制,因此这些对象之间并不会完全失去联系,它们是互相关联的。

new Foo() 会生成一个新对象(我们称之为 a),这个新对象的内部链接 [[Prototype]] 关联的是 Foo.prototype 对象。

最后我们得到了两个对象,它们之间互相关联,就是这样。我们并没有初始化一个类,实际上我们并没有从“类”中复制任何行为到一个对象中,只是让两个对象互相关联。

🌴

3.2 构造函数与类的误解

function Foo(){

}
var a=new Foo()

到底是什么让我们认为Foo是一个类呢?或者说类与构造函数的误解是什么?

我觉得有两个地方会让我们产生误解:

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

  • 对象的constructor属性的指向:

    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“构造”,🌱 稍后会解释的

3.3 构造函数是什么

上一节中的代码,我们使用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时,函数调用会变成“构造函数调用”

3.4 构造函数的属性是什么

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

这段代码中有两个有意思值得思考的点:

  • this.name=name给每个对象(这是在关于this的博客说过,是关于this的指向绑定)都添加了.name属性,,有点像实例封装数据值
  • Foo.prototype.myName = … 可能个更有趣的技巧,它会给 Foo.prototype 对象添加一个属性(函数)。现在,a.myName() 可以正常工作,但是你可能会觉得很惊讶,这是什么原理呢?

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

在本章开头介绍默认 [[Get]] 算法时我们介绍过 [[Prototype]] 链,以及当属性不直接存在于对象中时如何通过它来进行查找。

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

3.5 实例的constructor属性

回顾5.2.2中的一个问题:

❗️ 但是实际上a本身并没有.constructor属性,虽然 a.constructor 确实指向 Foo 函数,但是这个属性并不是表示 a 由 Foo“构造”,🌱 稍后会解释的

这个问题中,a.constructor === Foo为真,意味着a确实有指向Foo的.constructor属性,但是事实不是如此

🌳 实际上,.constructor引用同样被委托给了Foo.prototype,而Foo.prototype.constructor默认指向Foo。

把 .constructor 属性指向 Foo 看作是 a 对象由 Foo“构造”非常容易理解,但这只不过是一种虚假的安全感。a.constructor 只是通过默认的 [[Prototype]] 委托指向 Foo,这和“构造”毫无关系。相反,对于 .constructor 的错误理解很容易对你自己产生误导。

举例来说,Foo.prototype 的 .constructor 属性只是 Foo 函数在声明时的默认属性。如果你创建了一个新对象并替换了函数默认的 .prototype 对象引用,那么新对象并不会自动获得 .constructor 属性。

🤔 思考一下的代码:

![原型关系图](D:\学习专业资料\typora集合图片\你不知道的JavaScript笔记图片\原型关系图.jpg)function Foo(){ /* .. */ }

Foo.prototype={ /* .. */ }

var a1=new Foo()

a1.constructor === Foo //false
a1.constructor === Object //true

Object(…) 并没有“构造”a1,对吧?看起来应该是 Foo()“构造”了它。大部分开发者都认为是 Foo() 执行了构造工作,但是问题在于,如果你认为“constructor”表示“由……构造”的话,a1.constructor 应该是 Foo,但是它并不是 Foo !

到底怎么回事? a1 并没有 .constructor 属性,所以它会委托 [[Prototype]] 链上的 Foo.prototype。但是这个对象也没有 .constructor 属性(不过默认的 Foo.prototype 对象有这个属性!),所以它会继续委托,这次会委托给委托链顶端的 Object.prototype。这个对象有 .constructor 属性,指向内置的 Object(…) 函数。

5.3 (原型)继承

实际上,我们已经了解了通常被称作原型继承的机制,a可以继承Foo.prototype并访问Foo.prototype的myName()函数,但是我们之前只把继承看作是类是实例的关系,并没有把它看作是类是和类的关系:
原型描述

上面的那张关系图里,它不仅展示出对象(实例)a1 到 Foo.prototype 的委托关系,还展示出Bar.prototype 到 Foo.prototype 的委托关系,而后者和类继承很相似,只有箭头的方向不同。图中由下到上的箭头表明这是委托关联,不是复制操作。

下面这段代码使用的就是典型的“原型风格”

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”。

声明 function Bar() { … } 时,和其他函数一样,Bar 会有一个 .prototype 关联到默认的对象,但是这个对象并不是我们想要的 Foo.prototype。因此我们创建了一个新对象并把它关联到我们希望的对象上,直接把原始的关联对象抛弃掉。

😄 如果有不明白为什么this指向a的话,可以查看上一篇博客
学习JavaScript的this的使用和原理这一篇就够了,超详细

❗️ 注意,下面这两种方式是替换原型常见的错误:

// 和你想要的机制不一样!
Bar.prototype = Foo.prototype;

// 基本上满足你的需求,但是可能会产生一些副作用 :
Bar.prototype = new Foo();

Bar.prototype = Foo.prototype 并不会创建一个关联到 Bar.prototype 的新对象,它只是让 Bar.prototype 直接引用 Foo.prototype 对象。因此当你执行类似Bar.prototype.myLabel = … 的赋值语句时会直接修改 Foo.prototype 对象本身。显然这不是你想要的结果,否则你根本不需要 Bar 对象,直接使用 Foo 就可以了,这样代码也会更简单一些。

Bar.prototype = new Foo() 的确会创建一个关联到 Bar.prototype 的新对象。但是它使用了 Foo(…) 的“构造函数调用”,如果函数 Foo 有一些副作用(比如写日志、修改状态、注册到其他对象、给 this 添加数据属性,等等)的话,就会影响到 Bar() 的“后代”,后果不堪设想。

因此,要创建一个合适的关联对象,我们必须使用 Object.create(…) 而不是使用具有副作用的 Foo(…)。这样做唯一的缺点就是需要创建一个新对象然后把旧对象抛弃掉,不能直接修改已有的默认对象。

4 对象关联

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

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

4.1 创建关联

我们可以使用Object.create()来创建对象之间的关联,非常简单和方便

var foo = {
something: function() {
console.log( "Tell me something good..." );
}
};
var bar = Object.create( foo );
bar.something(); // Tell me something good

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

📝 Object.create(null) 会 创 建 一 个 拥 有 空( 或 者 说 null)[[Prototype]]链接的对象,这个对象无法进行委托。这些特殊的空 [[Prototype]] 对象通常被称作“字典”,它们完全不会受到原型链的干扰,因此非常适合用来存储数据。

我们并不需要类来创建两个对象之间的关系,只需要通过委托来关联对象就足够了。而Object.create(…) 不包含任何“类的诡计”,所以它可以完美地创建我们想要的关联关系。

Object.create()的替代代码

Object.create(…) 是在 ES5 中新增的函数,所以在 ES5 之前的环境中(比如旧 IE)如果要支持这个功能的话就需要使用一段简单的代码片段,它部分实例了Object.create(…)的功能

if (!Object.create) {
	Object.create = function(o) {
		function F(){}
		F.prototype = o;
		return new F();
	};
}

这段 polyfill 代码使用了一个一次性函数 F,我们通过改写它的 .prototype 属性使其指向想要关联的对象,然后再使用 new F() 来构造一个新对象进行关联

4.2 关联关系的意义

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

🤔 思考以下的代码:

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

var myObject = Object.create( anotherObject );

myObject.cool(); // "cool!"

由于存在 [[Prototype]] 机制,这段代码可以正常工作。但是如果你这样写只是为了让myObject 在无法处理属性或者方法时可以使用备用的 anotherObject,那么你的软件就会变得有点“神奇”,而且很难理解和维护。

这并不是说任何情况下都不应该选择备用这种设计模式,但是这在 JavaScript 中并不是很常见。所以如果你使用的是这种模式,那或许应当退后一步并重新思考一下这种模式是否合适。

在 ES6 中有一个被称为“代理”(Proxy)的高端功能,它实现的就是“方法无法找到”时的行为,如果有想了解的小伙伴,可以查看我的一篇博客
JavaScript的Proxy的使用和详情,还有代理的概念问题

当你给开发者设计软件时,假设要调用 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!"

这里我们调用的 myObject.doCool() 是实际存在于 myObject 中的,这可以让我们的 API 设计更加清晰(不那么“神奇”)。从内部来说,我们的实现遵循的是委托设计模式(参见下一章),通过 [[Prototype]] 委托到 anotherObject.cool()。

换句话说,内部委托比起直接委托可以让 API 接口设计更加清晰

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Some/IP学习笔记

目录 1.概述 2.SOME/IP 报文格式 3.数据结构序列化 1.概述 SOME/IP全称为Scalable Service Oriented MiddlewarE Over IP,是车载以太网技术中的核心内容,它为网络提供了面向服务的通信方式。一个服务可以包含0个或者多个事件(events&#…

flutter逆向 ACTF native app

前言 算了一下好长时间没打过CTF了,前两天看到ACTF逆向有道flutter逆向题就过来玩玩啦,花了一个下午做完了.说来也巧,我给DASCTF十月赛出的逆向题其中一道也是flutter,不过那题我难度降的相当之低啦,不知道有多少人做出来了呢~ 还原函数名 flutter逆向的一大难点就是不知道l…

常见面试题-Redis底层的SDS、ZipList、ListPack

Redis 的 SDS 了解吗? 答: Redis 创建了 SDS(simple dynamic string) 的抽象类型作为 String 的默认实现 SDS 的结构如下: struct sdshdr {// 字节数组,用于保存字符串char buf[];// buf[]中已使用字节…

介绍YOLO-NAS Pose:姿势估计的技术

YOLO-NAS 姿势 YOLO-NAS Pose models是对 Pose Estimation 领域的最新贡献。今年早些时候,Deci 因其突破性的目标检测基础模型 YOLO-NAS 获得了广泛认可。在 YOLO-NAS 成功的基础上,该公司现在推出了 YOLO-NAS Pose 作为其姿势估计的对应产品。该姿势模型在延迟和准确性之间…

linux入门---自旋锁和读写锁

自旋锁 首先通过一个例子来带着大家理解自旋锁,在生活中大家肯定都等过人比如你们一家人准备出去玩可是出发的时候妻子发现自己还没有化妆于是连忙赶回了家这个时候其他人就得在楼下等着,但是这个等又分为两种情况第一种是真的在楼下等其他的什么事都没…

DeCLIP 论文阅读

DeCLIP:supervision exists everywhere:a data efficient contrastive language-image pre-training paradigm 贡献: 论文是为了充分利用单模态和多模态,充分利用单模态特征用自监督(SIMSAM和MLM),多模态用图像文本对…

P6入门:项目初始化4-项目详情之预算日志及汇总Budget

前言 使用项目详细信息查看和编辑有关所选项目的详细信息,在项目创建完成后,初始化项目是一项非常重要的工作,涉及需要设置的内容包括项目名,ID,责任人,日历,预算,资金,分类码等等&…

ELK之Logstash解析时间相差8h的问题

一、问题描述 服务器当前时间为:2022年 06月 28日 星期二 11:24:22 CST 而logstash解析的时间为2022-06-28T03:15:25.545Z与实际时间相差8h 一、解决办法: 需改logstash的配置文件: 原理就是:定义一个中间变量timestamp&…

Unity如何保存场景,如何导出工程文件/如何查看保存位置?【各版本通用】

如何保存场景? 在unity中CtrlS 或者File—>Save 输入你要保存的场景名【建议保存在Scenes文件夹下】 下图,保存场景不在Scenes文件夹下: 下图,保存在Scenes文件夹下: 下图,保存完成 如何导出工程文…

nginx配置和热部署实践

目录 一、nginx配置文件 1.配置文件 2.nginx配置文件语法 3.include 二、nginx.conf参数 1.user参数 2.nginx.conf重要的指令块 3.nginx命令行 三、nginx热部署功能实践 1.热部署的特点 2.大致流程 3.环境准备 4.备份旧nginx二进制文件 5.下载编译安装新的nginx …

Mac电脑配置Flutter开发环境

1.进入官网下载页: Flutter SDK releases | Flutter 可以看到有 Windows、macOS、Linux三种系统的下载包 选择macOS,然后点击下载 Stable channel(稳定版)中的最新版本,下载完成后可以移动到资源库Library中。 2.下载…

Unity Input System最简单使用

开始学的是 Input Manager 比较好理解,Input System却不好理解,教程也找了很多,感觉都讲的不清楚,我这里做一个最简单的用 Input System 添加鼠标左键和右键的效果。 1. 安装 Input System 包 首先这个功能不是内置的&#xff0…

Flutter笔记:使用Flutter构建响应式PC客户端/Web页面-案例

Flutter笔记 使用Flutter构建响应式PC客户端/Web页面-案例 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article/detai…

红黑树,AVLTree树(平衡二叉树)迭代器原理讲解

红黑树,AVLTree树底层实现逻辑都是平衡二叉树(AVLTree高度平衡,红黑树以某种规则平衡),但终究不像链表的迭代器那样逻辑简单。 简单叙述以下,二叉树上面迭代器的运行逻辑,根据下面的图&#xff…

leetcode-链表经典题

1.反转单链表 206. 反转链表https://leetcode.cn/problems/reverse-linked-list/这里我们使用创建一个变量cur来遍历原链表,再创建一个新节点newnode,首先使用一个循环来遍历原链表,cur为NULL是循环结束,每次进入循环将cur的下一…

.mallab勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复

导言: .mallab勒索病毒是一种极具威胁性的数字病毒,通过高级加密算法深度侵袭用户文件,迫使受害者支付赎金以获取解密密钥。了解其侵害方式和对抗手段对数字安全至关重要。数据的重要性不容小觑,您可添加我们的技术服务号&#x…

threejs(12)-着色器打造烟雾水云效果

一、自己封装水波纹效果 src/main/main01.js import * as THREE from "three";import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import gsap from "gsap"; import * as dat from "dat.gui"; import ver…

【文件IO】

文章目录 File常见方法和属性属性构造方法方法 InputStream方法FileInputStream OutputStream利用 OutputStreamWriter 进行字符写入 总结按字节读取数据按字节写入数据按字符读取数据按字符写入数据 File常见方法和属性 属性 修饰符及类型属性说明static StringpathSeparato…

网络安全(黑客技术)-高效自学

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高; 二、则是发展相对成熟…

思科设备静态路由配置

一、静态路由基本知识 路由器的主要功能就是用来转发IP 数据包以使数据包到达正确的目的主机。可以想象数据包到达路由器就像一辆汽车开到十字路口,路由表就类似路标,列出可能到达的目的地,以及应该选择哪条路到达目的地。 路由器必须要有相应…