JavaScript核心编程 - 原型链 作用域 与 执行上下文

原型

在JavaScript中,每个对象都有一个内部属性,称为__proto__(在ES6中,这个属性被Object.getPrototypeOf()和Object.setPrototypeOf()方法标准化),这个属性指向该对象的原型。原型本身也是一个对象,这意味着它也有自己的原型,以此类推,形成一个链式结构。

当你尝试访问一个对象的属性时,如果该对象本身没有这个属性,JavaScript引擎会沿着这个链向上查找,直到找到该属性或者到达链的末端(即Object.prototype的原型是null)

原型链

原型链是对象之间的一系列原型链接。当你创建一个新对象时,你可以通过构造函数的prototype属性来指定新对象的原型。这样,新对象就可以继承原型对象的属性和方法。

例如,如果你有一个构造函数Person,并且你创建了一个新的Person实例p,那么p的原型就是Person.prototype。如果p没有某个属性或方法,JavaScript会查找Person.prototype是否有这个属性或方法,如果没有,再继续查找Person.prototype的原型,以此类推。

创建对象方式 - 构造函数创建对象

function Person() {​
​
}var person = new Person();​
person.name = 'Jerry';​
console.log(person.name) // Jerry

在这个例子中,Person 就是一个构造函数,我们使用 new 创建了一个实例对象 person。

prototype

每个函数都有一个 prototype 属性,比如:

function Person() {​
​
}// prototype是函数才会有的属性​
Person.prototype.name = 'Jerry';​
​
var person1 = new Person();var person2 = new Person();​
​
console.log(person1.name) // Jerry​
console.log(person2.name) // Jerry

那这个函数的 prototype 属性到底指向的是什么呢?是这个函数的原型吗?​
其实,函数的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型,也就是这个例子中的 person1 和 person2 的原型。​
那什么是原型呢?可以这样理解:每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。​
用一张图表示构造函数和实例原型之间的关系:
在这里插入图片描述
这里用 Object.prototype 表示实例原型。​
那么该怎么表示实例与实例原型,也就是 person 和 Person.prototype 之间的关系呢?

proto属性

这是每一个JavaScript对象(除了 null )都具有的一个属性,叫__proto__,这个属性会指向该对象的原型。

function Person() {​
​
}var person = new Person();​
​
console.log(person.__proto__ === Person.prototype); // true

在这里插入图片描述
既然实例对象和构造函数都可以指向原型,那么原型是否有属性指向构造函数或者实例呢?

constructor

指向实例倒是没有,因为一个构造函数可以生成多个实例,但是原型指向构造函数是有的:constructor,每个原型都有一个 constructor 属性指向关联的构造函数。

function Person() {​
​
}​
console.log(Person === Person.prototype.constructor); // true

在这里插入图片描述
所以,这里可以得到:

function Person() {​
​
}​
​
var person = new Person();​
​
console.log(person.__proto__ == Person.prototype) // true​
​
console.log(Person.prototype.constructor == Person) // true​
​
console.log(Object.getPrototypeOf(person) === Person.prototype) // true

实例与原型

当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。​
举个例子:

function Person() {​
​
}​
​
Person.prototype.name = 'Jerry';​
​
var person = new Person();​
​
person.name = 'Tom';​
console.log(person.name) // Jerry​delete person.name;​
console.log(person.name) // Tom

在这个例子中,我们给实例对象 person 添加了 name 属性,当我们打印 person.name 的时候,结果自然为 huaicheng。​
但是当我们删除了 person 的 name 属性时,读取 person.name,从 person 对象中找不到 name 属性就会从 person 的原型也就是 person.proto ,也就是 Person.prototype中查找,结果为 chenghuai。

原型的原型

其实原型对象就是通过 Object 构造函数生成的,结合之前所讲,实例的 proto 指向构造函数的 prototype ,所以我们再更新下关系图:
在这里插入图片描述

原型链

那 Object.prototype 的原型呢?​
null,我们可以打印:

console.log(Object.prototype.__proto__ === null) // true

然而 null 究竟代表了什么呢?​
null 表示“没有对象”,即该处不应该有值。​
所以 Object.prototype.proto 的值为 null 跟 Object.prototype 没有原型,其实表达了一个意思。​
所以查找属性的时候查到 Object.prototype 就可以停止查找了。​
最后一张关系图也可以更新为:
在这里插入图片描述
其中,蓝色为原型链。

其他相关

构造函数

首先是 constructor 属性:

function Person() {​
​
}var person = new Person();​
​
console.log(person.constructor === Person); // true

当获取 person.constructor 时,其实 person 中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person 的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以:

person.constructor === Person.prototype.constructor

proto

绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.proto 时,可以理解成返回了 Object.getPrototypeOf(obj)。

继承

关于继承,前面提到“每一个对象都会从原型‘继承’属性”,实际上,继承是一个十分具有迷惑性的说法,引用《你不知道的JavaScript》中的话,就是:​

继承意味着复制操作,然而 JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些。​

词法作用域和动态作用域

作用域

作用域是指程序源代码中定义变量的区域。​
作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限
JavaScript 采用词法作用域(lexical scoping),也就是静态作用域。

静态作用域和动态作用域

因为 JavaScript 采用的是词法作用域,函数的作用域在函数定义的时候就决定了。​
而与词法作用域相对的是动态作用域,函数的作用域是在函数调用的时候才决定的。

var value = 1;​
​
function foo() {​console.log(value);}​
​
function bar() {var value = 2;foo();}bar();

假设JavaScript采用静态作用域,让我们分析下执行过程:​
执行 foo 函数,先从 foo 函数内部查找是否有局部变量 value,如果没有,就根据书写的位置,查找上面一层的代码,也就是 value 等于 1,所以结果会打印 1。​
假设JavaScript采用动态作用域,让我们分析下执行过程:​
执行 foo 函数,依然是从 foo 函数内部查找是否有局部变量 value。如果没有,就从调用函数的作用域,也就是 bar 函数内部查找 value 变量,所以结果会打印 2。​
前面我们已经说了,JavaScript采用的是静态作用域,所以这个例子的结果是 1。

动态作用域

什么语言是动态作用域?​
bash 就是动态作用域,不信的话,把下面的脚本存成例如 scope.bash,然后进入相应的目录,用命令行执行 bash ./scope.bash,看看打印的值是多少。

value=1function foo () {​echo $value;}function bar () {​local value=2;​foo;}​
bar

思考

看一个面试题:

// case 1​
var scope = "global scope";function checkscope(){var scope = "local scope";function f(){return scope;}return f();}checkscope();​
​
// case 2​
var scope = "global scope";function checkscope(){var scope = "local scope";function f(){return scope;}return f;}checkscope()();

执行上下文

执行顺序

写过 JavaScript 的开发者都会有个直观的印象,那就是顺序执行:

var foo = function () {​
​console.log('foo1');​
​
}​
​
foo();  // foo1​var foo = function () {​
​console.log('foo2');​
​
}​
​
foo(); // foo2

那这段呢?

function foo() {​
​console.log('foo1');​
​
}​
​
foo();  // foo2​function foo() {​
​console.log('foo2');​
​
}​
​
foo(); // foo2

打印的结果却是两个 foo2。​
这是因为 JavaScript 引擎并非一行一行地分析和执行程序,而是一段一段地分析执行。当执行一段代码的时候,会进行一个“准备工作”,那这个“一段一段”中的“段”究竟是怎么划分的呢?​
到底JavaScript引擎遇到一段怎样的代码时才会做“准备工作”呢?

console.log(add2(1,1)); //输出2​
function add2(a,b){return a+b;}​
console.log(add1(1,1));  //报错:add1 is not a function​
var add1 = function(a,b){return a+b;}​
​
// 用函数语句创建的函数add2,函数名称和函数体均被提前,在声明它之前就使用它。​
// 但是使用var表达式定义函数add1,只有变量声明提前了,变量初始化代码仍然在原来的位置,没法提前执行。

可执行代码

这就要说到 JavaScript 的可执行代码(executable code)的类型有哪些了?​
其实很简单,就三种,全局代码、函数代码、eval代码。​
举个例子,当执行到一个函数的时候,就会进行准备工作,这里的“准备工作”,让我们用个更专业一点的说法,就叫做"执行上下文(execution context)"。

执行上下文栈

JavaScript 引擎创建了执行上下文栈(Execution context stack,ECS)来管理执行上下文​
为了模拟执行上下文栈的行为,让我们定义执行上下文栈是一个数组:

ECStack = [];

试想当 JavaScript 开始要解释执行代码的时候,最先遇到的就是全局代码,所以初始化的时候首先就会向执行上下文栈压入一个全局执行上下文,我们用 globalContext 表示它,并且只有当整个应用程序结束的时候,ECStack 才会被清空,所以程序结束之前, ECStack 最底部永远有个 globalContext:

ECStack = [​globalContext​
];
function fun3() {​console.log('fun3')}​
​
function fun2() {fun3();}​
​
function fun1() {fun2();}​
​
fun1();

当执行一个函数的时候,就会创建一个执行上下文,并且压入执行上下文栈,当函数执行完毕的时候,就会将函数的执行上下文从栈中弹出。知道了这样的工作原理,让我们来看看如何处理上面这段代码:

// 伪代码​// fun1()​
ECStack.push(<fun1> functionContext);​
​
// fun1中竟然调用了fun2,还要创建fun2的执行上下文​
ECStack.push(<fun2> functionContext);​
​
// 擦,fun2还调用了fun3!​
ECStack.push(<fun3> functionContext);​
​
// fun3执行完毕​
ECStack.pop();​
​
// fun2执行完毕​
ECStack.pop();​
​
// fun1执行完毕​
ECStack.pop();​
​
// javascript接着执行下面的代码,但是ECStack底层永远有个globalContext

回顾上文

// case 1​
var scope = "global scope";function checkscope(){var scope = "local scope";function f(){return scope;}return f();}checkscope();​
​
// case 2​
var scope = "global scope";function checkscope(){var scope = "local scope";function f(){return scope;}return f;}checkscope()();

两段代码执行的结果一样,但是两段代码究竟有哪些不同呢?​
答案就是执行上下文栈的变化不一样。​
模拟第一段代码:

ECStack.push(<checkscope> functionContext);​
ECStack.push(<f> functionContext);​
ECStack.pop();​
ECStack.pop();

模拟第二段:

ECStack.push(<checkscope> functionContext);​
ECStack.pop();​
ECStack.push(<f> functionContext);​
ECStack.pop();

这就是上文说到的区别。

变量对象

基础

当 JavaScript 代码执行一段可执行代码(executable code)时,会创建对应的执行上下文(execution context)。​

  • 对于每个执行上下文,都有三个重要属性:​
  • 变量对象(Variable object,VO);​
  • 作用域链(Scope chain);​
  • this;​

这里着重讲变量对象的内容

变量对象

变量对象是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。​
因为不同执行上下文下的变量对象稍有不同,所以我们来聊聊全局上下文下的变量对象和函数上下文下的变量对象。

全局上下文

  • 全局对象是预定义的对象,作为 JavaScript 的全局函数和全局属性的占位符。通过使用全局对象,可以访问所有其他所有预定义的对象、函数和属性。​
  • 在顶层 JavaScript 代码中,可以用关键字 this 引用全局对象。因为全局对象是作用域链的头,这意味着所有非限定性的变量和函数名都会作为该对象的属性来查询。​
  • 例如,当JavaScript 代码引用 parseInt() 函数时,它引用的是全局对象的 parseInt 属性。全局对象是作用域链的头,还意味着在顶层 JavaScript 代码中声明的所有变量都将成为全局对象的属性。

简单点说:​
1.可以通过 this 引用,在客户端 JavaScript 中,全局对象就是 Window 对象。

console.log(this);

2.全局对象是由 Object 构造函数实例化的一个对象。

console.log(this instanceof Object);

3.预定义的属性是否可用​

console.log(Math.random());​
console.log(this.Math.random());

4.作为全局变量的宿主

var a = 1;​
console.log(this.a);

5.客户端 JavaScript 中,全局对象有 window 属性指向自身

var a = 1;​
console.log(window.a);​
​
this.window.b = 2;​
console.log(this.b);

函数上下文

在函数上下文中,我们用活动对象(activation object, AO)来表示变量对象。​
活动对象和变量对象其实是一个东西,只是变量对象是规范上的或者说是引擎实现上的,不可在 JavaScript 环境中访问,只有到当进入一个执行上下文中,这个执行上下文的变量对象才会被激活,所以才叫 activation object,而只有被激活的变量对象,也就是活动对象上的各种属性才能被访问。​
活动对象是在进入函数上下文时刻被创建的,它通过函数的 arguments 属性初始化。arguments 属性值是 Arguments 对象。

执行过程

执行上下文的代码会分成两个阶段进行处理:分析和执行,我们也可以叫做:​

  • 进入执行上下文;​
  • 代码执行;

进入执行上下文

当进入执行上下文时,这时候还没有执行代码,​
变量对象会包括:​

  • 函数的所有形参 (如果是函数上下文)​
    由名称和对应值组成的一个变量对象的属性被创建;​
    没有实参,属性值设为 undefined;​
  • 函数声明​
    由名称和对应值(函数对象(function-object))组成一个变量对象的属性被创建;​
    如果变量对象已经存在相同名称的属性,则完全替换这个属性;​
  • 变量声明​
    由名称和对应值(undefined)组成一个变量对象的属性被创建;​
    如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性;


举个例子:

function foo(a) {var b = 2;function c() {}var d = function() {};​
​b = 3;​
​
}​
​
foo(1);

在进入执行上下文后,这时候的 AO 是:

AO = {​arguments: {0: 1,​length: 1},​a: 1,​b: undefined,​c: reference to function c(){},​d: undefined}

执行阶段

在代码执行阶段,会顺序执行代码,根据代码,修改变量对象的值​
还是上面的例子,当代码执行完后,这时候的 AO 是:

AO = {​arguments: {0: 1,​length: 1},​a: 1,​b: 3,​c: reference to function c(){},​d: reference to FunctionExpression "d"}

到这里变量对象的创建过程就介绍完了,让我们简洁的总结我们上述所说:​

  • 全局上下文的变量对象初始化是全局对象;​
  • 函数上下文的变量对象初始化只包括 Arguments 对象;​
  • 在进入执行上下文时会给变量对象添加形参、函数声明、变量声明等初始的属性值;​
  • 在代码执行阶段,会再次修改变量对象的属性值;

练习

function foo() {​console.log(a);​a = 1;}​
​
foo(); // ???​function bar() {​a = 1;​console.log(a);}bar(); // ???

第一段会报错:Uncaught ReferenceError: a is not defined。​
第二段会打印:1。​
这是因为函数中的 “a” 并没有通过 var 关键字声明,所有不会被存放在 AO 中。​
第一段执行 console 的时候, AO 的值是:

AO = {​arguments: {​length: 0}}

没有 a 的值,然后就会到全局去找,全局也没有,所以会报错。​
当第二段执行 console 的时候,全局对象已经被赋予了 a 属性,这时候就可以从全局找到 a 的值,所以会打印 1。​
example 2

console.log(foo);​
​
function foo(){​console.log("foo");}​
​
var foo = 1;

作用域链

上文讲到,当JavaScript代码执行一段可执行代码(executable code)时,会创建对应的执行上下文(execution context)。​
对于每个执行上下文,都有三个重要属性:​

  • 变量对象(Variable object,VO)​
  • 作用域链(Scope chain)​
  • this​

作用域链​

上节讲到,当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。

函数创建

上文的词法作用域与动态作用域中讲到,函数的作用域在函数定义的时候就决定了。​
这是因为函数有一个内部属性 [[scope]],当函数创建的时候,就会保存所有父变量对象到其中,你可以理解 [[scope]] 就是所有父变量对象的层级链,但是注意:[[scope]] 并不代表完整的作用域链!​
举个例子:

function foo() {function bar() {...}}

函数创建时,各自的[[scope]]为:

foo.[[scope]] = [​globalContext.VO];​
​
bar.[[scope]] = [​fooContext.AO,​globalContext.VO];​
​

函数激活

当函数激活时,进入函数上下文,创建 VO/AO 后,就会将活动对象添加到作用链的前端。​
这时候执行上下文的作用域链,我们命名为 Scope:

Scope = [AO].concat([[Scope]]);

总结

结合着之前讲的变量对象和执行上下文栈,我们来总结一下函数执行上下文中作用域链和变量对象的创建过程:

var scope = "global scope";function checkscope(){var scope2 = 'local scope';return scope2;}checkscope();

执行过程如下:
1.checkscope 函数被创建,保存作用域链到 内部属性[[scope]]

checkscope.[[scope]] = [​globalContext.VO];

2.执行 checkscope 函数,创建 checkscope 函数执行上下文,checkscope 函数执行上下文被压入执行上下文栈

ECStack = [​checkscopeContext,​globalContext​
];

3.checkscope 函数并不立刻执行,开始做准备工作,第一步:复制函数[[scope]]属性创建作用域链

checkscopeContext = {​Scope: checkscope.[[scope]],}

4.第二步:用 arguments 创建活动对象,随后初始化活动对象,加入形参、函数声明、变量声明

checkscopeContext = {AO: {​arguments: {​length: 0},​scope2: undefined},​Scope: checkscope.[[scope]],}

5.第三步:将活动对象压入 checkscope 作用域链顶端

checkscopeContext = {AO: {​arguments: {​length: 0},​scope2: undefined},​Scope: [AO, [[Scope]]]}

6.准备工作做完,开始执行函数,随着函数的执行,修改 AO 的属性值

checkscopeContext = {AO: {​arguments: {​length: 0},​scope2: 'local scope'},​Scope: [AO, [[Scope]]]}

7.查找到 scope2 的值,返回后函数执行完毕,函数上下文从执行上下文栈中弹出

ECStack = [​globalContext​
];

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

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

相关文章

C++ 引用 详解

引用 引用 不是新定义一个变量&#xff0c;而 是给已存在变量取了一个别名 &#xff0c;编译器不会为引用变量开辟内存空 间&#xff0c;它和它引用的变量 共用同一块内存空间。 比如&#xff1a; 李逵 &#xff0c;在家称为 " 铁牛 " &#xff0c;江湖上人称 &qu…

计算机视觉中的中值滤波:经典案例与Python代码解析

Hey小伙伴们&#xff01;今天我们要聊的是计算机视觉中的一个重要技术——中值滤波。中值滤波是一种非线性滤波方法&#xff0c;主要用于去除图像中的椒盐噪声&#xff0c;同时保留图像的边缘和细节。通过中值滤波&#xff0c;我们可以显著改善图像的质量。让我们一起来看看如何…

【C++练习】计算前N项自然数之和

题目&#xff1a; 计算前N项自然数之和 描述&#xff1a; 编写一个C程序&#xff0c;要求用户输入一个整数N&#xff0c;然后计算并输出从1到N&#xff08;包括N&#xff09;的所有自然数之和。 程序功能要求&#xff1a; 程序首先提示用户输入一个整数N。使用一个循环结构…

SpringBoot日志配置

Spring默认日志风格 个人感觉默认的格式还是不错的&#xff0c;每一列都可以对其&#xff0c;而且能用颜色区分&#xff0c;查看日志明了&#xff1b; 下面是他默认的 pattern的配置 %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:%5p}) %clr(${PID:- …

Vue3学习笔记(上)

Vue3学习笔记&#xff08;上&#xff09; Vue3的优势&#xff1a; 更容易维护&#xff1a; 组合式API更好的TypeScript支持 更快的速度&#xff1a; 重写diff算法模板编译优化更高效的组件初始化 更小的体积&#xff1a; 良好的TreeShaking按需引入 更优的数据响应式&#xf…

看懂本文,入门神经网络Neural Network

神经网络&#xff08;Neural Network&#xff09; 1.1图片 每一个图片都是三维数组&#xff0c;每个像素的值为0-255&#xff0c;如 训练集Training Dataset&#xff1a;“上课学的知识”&#xff0c;用于训练模型得到参数 验证集Validation Dataset&#xff1a;“课后习题”…

Zoho Books助外贸,应收账款简化管

ZohoBooks财务管理软件助外贸企业精准管理客户信息&#xff0c;简化跨境开票&#xff0c;集成支付网关自动对账&#xff0c;智能提醒跟进账款&#xff0c;提供强大报表分析功能&#xff0c;支持多币种和当地税法&#xff0c;促进财务健康与资金回笼。 一、精准的客户信息管理 …

保姆级教程!!教你通过【Pycharm远程】连接服务器运行项目代码

小罗碎碎念 这篇文章主要解决一个问题——我有服务器&#xff0c;但是不知道怎么拿来写代码&#xff0c;跑深度学习项目。确实&#xff0c;玩深度学习的成本比较高&#xff0c;无论是前期的学习成本&#xff0c;还是你需要具备的硬件成本&#xff0c;都是拦路虎。小罗没有办法…

作业调度和程序装入内存

作业调度 我们知道&#xff0c;磁盘上的可执行程序只有装入内存&#xff0c;成为进程才可以运行。在磁盘上有许多的可执行程序等待被操作系统唤入内存执行&#xff0c;我们把可执行程序在磁盘上的调度称之为作业调度。 注意&#xff1a;这种说法听起来好像是作业在磁盘上的调…

广义布里渊区方程推导过程中一个公式的理解

是对DOI: 10.1103/PhysRevLett.123.066404补充材料公式(S25)的理解 clear;clc;close all q2; N1;Mq*N; syms LMatsym(zeros(2*M,2*M));for ii1:MTp[];for jj1:2*M%eval([syms , f,num2str(ii),num2str(jj)]);eval([syms ,f,num2str(ii),_beta,num2str(jj),_ES])%eval([temp,f,…

嵌入式linux中HDMI驱动操作方法

大家好,今天主要给大家分享一下,linux系统里面的HDMI驱动实现方法。 第一:HDMI基本简介 HDMI 全称为 High Definition Multimedia Interface,也就是高清多媒体接口,是一个纯数字的音视频传输接口,通过一根线同时发送音视频数据。目前在电视、显示器、电脑、机顶盒等领域得…

边缘的检测

边缘检测效果&#xff0c;是一种用于突出图像中的边缘&#xff0c;使物体的轮廓更加明显的图像处理技术&#xff0c;边缘检测的主要目的是找到图像中亮度变化显著的区域&#xff0c;这些区域通常对应于物体的边界&#xff0c;边缘检测相当于利用 Shader 代码自动给屏幕图像进行…

架构篇(05理解架构的服务演化)

目录 学习前言 一、服务演化简介 二、方向一&#xff1a;架构服务化 单体分层架构 面向服务架构 - SOA 微服务架构 - Microservices 云原生架构 - Cloud Native 三、方向二&#xff1a;部署容器编排化 虚拟机 容器 Kubernetes 与编排 四、参考文献 学习前言 Kubern…

娶老婆花了30万彩礼,结婚2个月,她前夫给我20万,让我老婆和他生孩子!

我叫李志强&#xff0c;今年32岁&#xff0c;在一家物流公司当经理。去年我娶了我老婆张美玲&#xff0c;为了这场婚礼&#xff0c;我花了30万彩礼。美玲比我小3岁&#xff0c;是个护士&#xff0c;长得漂亮又温柔&#xff0c;我觉得自己找到了真爱。 结婚前&#xff0c;美玲就…

基于SpringBoot的国风服装商城系统+LW示例参考

1.项目介绍 系统角色&#xff1a;管理员、普通用户功能模块&#xff1a;管理员&#xff08;用户管理、商品管理、分类管理、订单管理、系统管理、在线客服等&#xff09;&#xff0c;普通用户&#xff08;登录注册、个人中心、评价管理、收藏管理、订单管理等、咨询服务等&…

GB/T 43206—2023信息安全技术信息系统密码应用测评要求(五)

文章目录 附录AA.1 概述A.2 密钥产生A.3 密钥分发A.4 密钥存储A.5 密钥使用A.6 密钥更新A.7 密钥归档A. 8 密钥撤销A.9 密钥备份A.10 密钥恢复A.11 密钥销毁 附录B附录C 附录A A.1 概述 密钥管理对于保证密钥全生存周期的安全性至关重要 ,可以保证密钥(除公开密钥外) 不被非授…

jmeter常用配置元件介绍总结之前置处理器、测试片段

系列文章目录 安装jmeter jmeter常用配置元件介绍总结之前置处理器、测试片段 6.前置处理器6.1用户参数6.2取样器超时6.3.测试片段6.4JSR223 PreProcessor6.5.JDBC PreProcessor 6.前置处理器 在取样器请求之前执行的操作&#xff0c;优先级比取样器高&#xff0c;用来处理一些…

【IT人物系列】之Java之父

前言 当今世界由无数的人构成&#xff0c;其中有些人做了一些改变世界的事情&#xff0c;比如&#xff1a;乔布斯缔造了Apple帝国&#xff0c;‌詹姆斯高斯林创造了Java语言等。正是这些优秀的人做的这些优秀的事情&#xff0c;让这个世界更加美好。因此他们值得铭记。 从今天…

鸿蒙开发基础入门

一、熟悉目录结构 二、ArkTS语法介绍 ArkTS是为构建高性能应用设计的编程语言&#xff0c;语法继承TypeScript&#xff0c;并进行了优化&#xff0c;拥有更强的类型约束ArkTS提供了声明式UI范式&#xff0c;符合移动开发的最新趋势 ArkTS摒弃了部分影响运行时的性能的语法&…

大数据机器学习算法和计算机视觉应用01:博弈论基础

Game Theory 2-player Zero Sum GameMinimax Optimal StrategiesVon Neumann’s Minimax TheoremLower Bounds for Randomized AlgorithmsGeneral sum games, Nash quilibria (p.s:该系列是国际交流学术公开课的笔记&#xff0c;主讲人是Carnegie Melon University的终身教授…