【原型详解】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; // 2myObject.a; // 2anotherObject.hasOwnProperty( "a" ); // true
myObject.hasOwnProperty( "a" ); // falsemyObject.a++; // 隐式屏蔽!anotherObject.a; // 2
myObject.a; // 3myObject.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 //truevar 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 接口设计更加清晰

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

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

相关文章

Django视图函数和资源

文章目录 1.视图1.1 文件or文件夹1.2 相对和绝对导入urls1.3 视图参数1.4 返回值1.5 响应头1.6 FBV和CBV 2.静态资源2.1 静态文件2.2 媒体文件 1.视图 1.1 文件or文件夹 1.2 相对和绝对导入urls 注意实现:不要再项目根目录做相对导入。 原则: 绝对导入…

【强化学习】18 —— SAC( Soft Actor-Critic)

文章目录 前言最大熵强化学习不同动作空间下的最大熵强化学习基于能量的模型软价值函数最大熵策略 Soft Q-learningSoft Q-IterationSoft Q-Learning近似采样与SVGD伪代码 Soft Actor-Critic伪代码代码实践连续动作空间离散动作空间 参考与推荐 前言 之前的章节提到过在线策略…

iOS移动应用安全加固:保护您的App免受恶意攻击的重要步骤

目录 iOS移动应用安全加固:保护您的App免受恶意攻击的重要步骤 摘要 引言 一、APP加固的概念 二、APP加固方案的比较 三、保护iOS应用的安全 四、总结 参考资料 摘要 本文介绍了移动应用程序(App)加固的概念和流程,以及市…

【Unity细节】Unity中如何让组件失活而不是物体失活

👨‍💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 😶‍🌫️收录于专栏:unity细节和bug 😶‍🌫️优质专栏 ⭐【…

Python之Django

web应用程序 # Django框架是一款专门用来开发web应用的框架 # Web应用程序是一种可以通过浏览器访问的应用程序, B/S架构 案例:淘宝网、京东... # 应用程序有两种模式: C/S:客户端/服务器端程序,这类程序一般独立运行 B/S:…

Python之文件与文件夹操作及 pytest 测试习题

目录 1、文本文件读写基础。编写程序,在 当前目录下创建一个文本文件 test.txt,并向其中写入字符串 hello world。2、编写一个程序 demo.py,要求运行该程序后,生成 demo_new.py 文件,其中内容与demo.py 一样&#xff0…

文件管理技巧:按文件容量大小分类,自动移动至目标文件夹的方法

按文件容量大小分类可以帮助快速识别和筛选出不同大小的文件。这样做有很多好处。首先,可以轻松地查找和访问特定大小的文件,提高工作效率。其次,通过将不同大小的文件分类,可以更好地了解和掌控文件的使用情况,避免存…

springboot高校全流程考勤系统-计算机毕设 附源码 27637

Springboot高校全流程考勤系统 摘 要 本文针对高校考勤等问题,对其进行研究分析,然后开发设计出高校全流程考勤系统以解决问题。高校全流程考勤系统系统主要功能模块包括:考勤签到、课程信息、考勤情况、申请记录列表等,系统功能设…

牛客、赛码网OJ调试(全)

现在无论开发还是测试,面试的时候都需要考察代码能力。 从测试的职业发展来看,现在市场上对于纯功能测试的需求很少,招聘方均要求面试者一方面具备测试基础能力,也要求有点代码能力。 对于测试来说,除了测试开发&#…

自定义类型:联合和枚举

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1. 联合体 1.1 联合体类型的声明 1.2 联合体的特点 1.3 相同成员的结构体和联合体对比 1.4 联合体大小的计算 1.5 联合的一个练习 2. 枚举类型 2.1 枚举类型的声明…

Linux基础开发工具之分布式版本控制系统Git

文章目录 1.Git是什么?1.1介绍1.2影响世界的大牛1.3English Words 2.Git常用指令2.1Git三板斧2.2解决冲突2.3黑名单文件2.4删除本地远端 1.Git是什么? 1.1介绍 史上最浅显易懂的Git教程! git是一个软件 gitee/github是一个网站但是他们的主…

linux 下非sudo安装cmake

1.查看位数 getconf LONG_BIT2.下载对应压缩包 Download CMake Source Distribution 未编译源代码 Binary Distribution已经编译好的 3.解压至文件夹 tar -zxvf cmake-3.28.0-rc4-linux-x86_64.tar.gz 4.添加环境变量 vi ~/.bashrc 最后一行添加 写到bin目录 export P…

基于element-plus定义表格行内编辑配置化

文章目录 前言一、新增table组件二、使用步骤 前言 在 基于element-plus定义表单配置化 基础上,封装个Element-plus的table表格 由于表格不同于form组件,需自定义校验器,以下组件配置了单个校验,及提交统一校验方法,且…

spring-cloud-stream

系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 第五章 Spring Cloud Netflix 之 Ribbon 第六章 Spring Cloud 之 OpenFeign 第七章 Spring Cloud 之 GateWay 第八章 Sprin…

Gradio App生产环境部署教程

如果机器学习模型没有投入生产供人们使用,就无法充分发挥其潜力。 根据我们的经验,将模型投入生产的最常见方法是为其创建 API。 然而,我们发现这个过程对于 ML 开发人员来说可能相当令人畏惧,特别是如果他们不熟悉 Web 开发的话。…

汽车ECU的虚拟化技术初探(一)

目录 1.为什么要提汽车ECU的虚拟化? 2.虚拟化技术分类 2.1 硬件虚拟化 2.2 操作系统虚拟化 问题引入: Hypervisor是如何来管理和隔离硬件资源,保证各个不同功能的应用程序的资源使用安全和资源调度?没有MMU就做不了虚拟化&am…

4.HTML网页开发的工具

4. 网页开发的工具 4.1 快捷键 4.1.1 快速复制一行 快捷键:shiftalt下箭头(上箭头) 或者ctrlc 然后 ctrlv 4.1.2 选定多个相同的单词 快捷键: ctrld 4.1.3 添加多个光标 快捷键:ctrlalt上箭头(下箭头&…

CS224W6.2——深度学习基础

在本文中,我们回顾了深度学习的概念和技术,这些概念和技术对理解图神经网络至关重要。从将机器学习表述为优化问题开始,介绍了目标函数、梯度下降、非线性和反向传播的概念。 文章目录 1. 大纲2. 优化问题2.1 举例损失函数 3. 如何优化目标函…

MySQL on duplicate key update用法

基本使用方法 public static final String SQL_TQI_SINK "insert into " ConfigureContext.get(ConfigKeyConstants.MYSQL_TABLE_TQI) " \n" "(mile_km, mile_start_km, mile_start_m, is_out, tqi_alig_l, \n" "tqi_alig_r, tqi_surf_l…

Redis系列-Redis性能优化与安全【9】

目录 Redis系列-Redis性能优化与安全【9】Redis性能优化策略Redis安全设置与防护措施Redis监控与诊断工具介绍 七、Redis应用案例与实战八、Redis未来发展与趋势 个人主页: 【⭐️个人主页】 需要您的【💖 点赞关注】支持 💯 Redis系列-Redis性能优化与安…