当前位置: 首页 > news >正文

【JavaScript】原型链/作用域/this指针/闭包

1.原型链

参考资料:Annotated ES5

ECMAScript起初并不支持如C++、Smalltalk 或 Java 中“类”的形式创建对象,而是通过字面量表示法或者构造函数创建对象。每个构造函数都是一个具有名为“prototype”的属性的函数,该属性用于实现基于原型的继承和共享属性。通过在new表达式中使用构造函数来创建对象;例如,new Date(2009,11) 创建一个新的 Date 对象。

继承:指的是将特征从父级传递给子级,以便新的代码段可以重用并基于现有代码的特性进行构建。

原型对象:由构造函数创建的每个对象都对其构造函数的“prototype”属性的值有一个隐式引用(称为该对象的原型对象),即在下列代码中,称“Animal.prototype”为“animal的原型对象”,“Animal.prototype”本身也是个对象。

/*构造函数*/
function Animal(name,weight){this.name = namethis.weight = weight
}
/*在new表达式中使用构造函数创建的对象*/
const animal = new Animal('米粒',10)console.log('animal的原型:',Animal.prototype)

原型链:原型对象本身也有自己的原型,以此类推,直到到达一个原型为 null 的对象(null 没有原型而作为引用链的终点)。我们称这一条完整的隐式引用链为原型链(prototype chain)。原型链的作用是为了实现继承和共享属性。

__proto__:对象的内置属性(非标准的属性,但已经被绝大部分Javascript引擎实现,对应于ECMAScript中的[[prototype]],ECMAScript标准的获取对象原型的API是Object.getPrototypeOf() ),用于指向该对象的原型对象prototype,即:

/*构造函数*/
function Animal(name,weight){this.name = namethis.weight = weight
}
/*在new表达式中使用构造函数创建的对象*/
const animal = new Animal('米粒',10)console.log('animal的原型:',Animal.prototype)
console.log('animal的原型:',animal.__proto__)
console.log('animal.__proto__===Animal.prototype:',animal.__proto__===Animal.prototype)
/*通过Object.getPrototypeOf()规范地获取animal的原型*/
console.log('animal的原型:',Object.getPrototypeOf(animal))

constructor: 原型对象prototype上都有个预定义的constructor属性,用来引用它的函数对象。这是种循环引用的目的是允许人们从任何实例访问原始构造函数。

/*构造函数*/
function Animal(name,weight){this.name = namethis.weight = weight
}
/*在new表达式中使用构造函数创建的对象*/
const animal = new Animal('米粒',10)
// Animal.prototype.constructor === Animal: true
console.log('Animal.prototype.constructor === Animal:',Animal.prototype.constructor === Animal)

注意要点:
(1)构造函数是一个函数对象,所以其原型是Function.prototype。
(2)原型对象是一个对象,所以其原型是Object.prototype。
(3)Object.prototype.__proto__ 指向 null,null是原型链的终点。
(4)尝试访问对象的属性时,不仅要在对象上查找该属性,还要在对象的原型prototype、原型的原型等上查找该属性,直到找到具有匹配名称的属性或到达原型链的末尾。

完整原型链示例图:(其中Animal、Object、Function是构造函数)

2.作用域

参考文档:ECMA-262-5 in detail. Chapter 3.1. Lexical environments: Common Theory. – Dmitry Soshnikov

作用域(Scope):一个封闭的上下文,用于管理程序不同部分的变量的可见性和可访问性。我们也可以说,作用域是一个逻辑边界,其中的变量(或表达式)有其独特的含义。例如,全局变量、局部变量等,通常反映变量生存期(或范围)的逻辑范围。

作用域属性:嵌套、变量解析方式(静态作用域和动态作用域)。

作用域链:由于作用域可以逐层嵌套,所以各层作用域组成了一个逻辑链,我们称其为作用域链。当访问某个变量时,js引擎会从当前作用域开始在包裹当前作用域的父级作用域中查找,若未找到,则再向上查找父级作用域,以此类推。从执行上下文角度看,作用域链是由环境记录(EnvironmentRecord)中的外部环境引用属性(OuterEnv)串联而成。

块级作用域: ES6 之前, ECMAScript 不支持块级作用域:

var x = 10;if (true) {var x = 20;console.log(x); // 20
}console.log(x); // 20

可以通过立即调用函数表达式IIFE实现:

var x = 10;if (true) {(function (x) {console.log(x); // 20})(20);
}console.log(x); // 10

通过函数作用域隔离变量,实现了个性化块级作用域效果,这也是ES6之前js模块化开发的依据。直到ES6 中标准化了 let 关键字,创建块范围的变量就变得方便多了:

let x = 10;if (true) {let x = 20;console.log(x); // 20
}console.log(x); // 10

静态作用域:亦称词法作用域。在静态作用域中,标识符指向其最近的词法环境,变量的作用域在代码编写时就确定的,并且在程序执行期间不会改变。具有以下特点:

  1. 定义位置决定作用域:变量的可访问范围由其定义的位置决定。
  2. 函数内部的变量:只能在该函数内部访问和使用。
  3. 块级作用域:可能存在块级别的作用域,限制变量的可见性。
  4. 稳定性:在运行时作用域不会改变。

例如,下列例子中,变量 x 在全局作用域中进行了词法定义——这意味着在运行时它也在全局作用域中进行解析,即解析为10。而对于 y 这个变量,我们定义了两次。但正如前面所说,总是考虑包含该变量的最近的词法作用域。自身作用域具有最高优先级并被首先考虑。因此,在 bar 函数的情况下,y 变量被解析为 30。bar 函数的本地变量 y 被称为遮蔽了全局作用域中同名的变量 y。然而,在 foo 函数的情况下,同名的 y 被解析为 20——即使它是在包含另一个 y 的 bar 函数内部被调用的。也就是说,标识符的解析独立于调用者的环境(在这种情况下,bar 是 foo 的调用者,而 foo 是被调用者)。同样,这是因为在定义 foo 函数时,具有 y 名称的最近的词法上下文——是全局上下文。

var x = 10;
var y = 20;function foo() {console.log(x, y);
}foo(); // 10, 20function bar() {var y = 30;console.log(x, y); // 10, 30foo(); // 10, 20
}bar();

动态作用域:在程序运行时才能确定变量的作用域。在该作用域中,变量不是在词法环境中解析,而是在动态形成的全局变量堆栈环境中解析。每次遇到变量声明,只是将变量的名称放在堆栈上。变量的作用域(生命周期)结束后,变量将从堆栈中移除(弹出)。这意味着,对于单个函数,我们可能有相同变量名的无限解析方式——这取决于调用该函数的上下文。

Javascript使用的是静态作用域。虽然ECMAScript中的with指令和eval指令具有动态效果,但不像标准动态作用域定义中那样涉及全局变量堆栈,这两个指令对静态作用域起到的效果可以称之为:“Runtime scope augmentation”(运行时作用域增强)

可执行代码:在ECMAScript 中有三种可执行代码:
(1)全局代码global code:是被视为 ECMAScript 程序的源文本,在全局作用域中执行的代码。
(2)Eval 代码eval code:通过 eval 函数动态执行的字符串形式的代码。提供给内置 eval 函数的源文本。更准确地说,如果内置 eval 函数的参数是 String,则将其视为 ECMAScript 程序。特定调用的 eval 代码 eval 是该程序的全局代码部分。
(3)函数代码function code:作为 FunctionBody 的一部分进行分析的源文本,包含在函数定义内部的代码。

全局代码在程序的任何地方都可以访问和执行。函数体代码只有在函数被调用时才会执行。eval 函数可以动态地解析和执行字符串中的代码,但由于其安全性和性能方面的考虑,在实际开发中应谨慎使用。

每种可执行代码在执行前,会经js引擎编译并创建对应的执行上下文。全局代码在全局上下文中执行,函数代码在函数上下文中执行,Eval代码在Eval上下文中执行。每一个js文件只有一个全局上下文。

执行上下文:包含跟踪其关联代码的执行进度所需的任何状态。每个执行上下文均包含三个状态组件:
(1)词法环境(LexicalEnvironment):用于实现作用域。包含两个组成部分:

  • 环境记录(EnvironmentRecord):将变量名映射到变量值(类似于Map)。作用域变量的实际存储空间。记录中的「名称-值」条目称为绑定。
  • 对外部环境的引用(OuterEnv):当前可以访问的外部词法环境,是一个抽象类,有3个具体的子类:
    A.声明式环境记录:又派生出函数环境记录和module环境记录。
    B.对象环境记录;
    C.全局环境记录。

    因此,可以认为存在三种作用域:
    A.声明式作用域:可以通过 var/const/let/class/module/import/function生成。ES6块级作用域是函数作用域的子级。
    B.对象作用域:使用with关键字指定代码块的作用域范围:
    function test(){let ob = { name:'javascript' };// 利用with扩展了作用域with(ob){console.log(`Hello ${name}`)}
    }test(); // Hello javascript

    C.全局作用域:最外层的作用域。Outer Env为null。通过声明式环境记录(使用内部对象存储变量)和对象环境记录(将变量存储在全局对象中)来管理变量。

(2)变量环境(VariableEnvironment):本质是一个对象,记录此执行上下文中由 VariableStatements 和 FunctionDeclarations 定义的变量和函数(即var和function声明的标识符)。
(3)this绑定(ThisBinding):与此执行上下文关联的 ECMAScript 代码中 this 的关键字关联的值。

ES6中执行到代码块时,如果代码块中有 let 或者 const 声明的变量,针对变量的查询路径为: 1. 词法环境 2. 变量环境 3. OuterEnv对象(上一层作用域继续先1后2)

工作过程:当控制转移到 ECMAScript 可执行代码时,控制正在进入执行上下文。活动执行上下文在逻辑上形成一个堆栈。此逻辑堆栈上的顶级执行上下文是正在运行的执行上下文。每当将控制从与当前正在运行的执行上下文关联的可执行代码传输到与该执行上下文无关的可执行代码时,都会创建一个新的执行上下文。新创建的执行上下文被推送到堆栈上,并成为正在运行的执行上下文。

作用域和执行上下文的关系:作用域是执行上下文有权访问的一组有限的变量或对象,同一个执行上下文上可能存在多个作用域,每个执行上下文均有自己的作用域。

执行上下文堆栈(ECS:Execution context Stack)ECS:ECMAScript 用来管理函数执行的调用堆栈模型称为执行上下文堆栈。工作过程如下:

  • 首先创建全局执行上下文, 压入栈底
  • 每当调用一个函数时,创建函数的函数执行上下文。并且压入栈顶
  • 当函数执行完成后,会从执行上下文栈中弹出,js引擎继续执栈顶的函数。

变量提升:js代码在执行前还有一个编译的过程,在编译过程中,var变量和function函数部分会被js引擎放入到对应上下文的变量环境中,并且变量会被默认设置为undefined。在执行阶段,js引擎才会在变量环境中查找到声明的变量和函数。在程序员角度看来,就出现了变量在声明前就可以访问,并且函数在定义之前便可调用的现象。我们称该现象为变量提升。
需要注意的是,var变量只有创建和初始化被提升,赋值并没有被提升;而function的创建、初始化和赋值均会被提升。所以在变量的声明之前访问,该变量的值是undefined,而函数则可以在声明之前正常调用。

暂时性死区:ES6中引入了let、const关键字,解决了变量提升问题,使得js支持块级作用域。严格意义上,letconst没有解决变量提升问题,当js代码被编译时,letconst变量代码会被存放在词法环境中。此时letconst变量已经被提升到了作用域顶部,但是只是声明被提升,初始化和赋值并没有被提升,如果在赋值代码行之前去读写该变量,便会报错。我们将这种从作用域开始到赋值变量代码之前暂时无法读写对应变量的区域称为“暂时性死区”

头等函数( first-class functions ):可以以变量使用的函数,如:将函数作为另一个函数的参数,将函数赋值给变量,将函数作为另一个函数的返回值。Javascript就是具有头等函数的语言。

高阶函数:满足两个条件之一的函数:接受函数作为参数传递的函数;返回一个另一个函数的函数。

回调函数:被当做参数传递给另一个函数的函数。

3.this指针

        this是一个的关键字,用于指向一段代码(如函数的主体)应该运行的上下文。JavaScript 中“this”的值取决于函数是如何被调用的(即运行时绑定),而不是它是如何被定义的。
        当一个普通函数作为对象的方法被调用(obj.method())时,“this”指向该对象。
        当作为一个独立的函数被调用(没有附着在任何一个对象上:func())时,“this”通常指的是全局对象(在非严格模式下)或undefined(在严格模式下)。Function.prototype.bind()方法可以创建一个“this”绑定不会改变的函数,并且方法 apply()和 call()也可以为特定的调用设置“this”值。
        箭头函数在处理 this 时有所不同:它们在定义时从父作用域继承 this。这种行为使箭头函数对于回调和保留上下文特别有用。然而,箭头函数没有自己的 this 绑定。因此,它们的 this 值不能通过 bind()、apply() 或 call() 方法进行设置。

在非严格模式下, this 始终指向一个对象。在严格模式下,可以指向任何值。this的取值由其出现的上下文环境决定,具体情况如下:

(1)函数上下文

在函数内部,this 的值取决于函数如何被调用。可以将 this 看作是函数的一个隐藏参数(就像函数定义中声明的普通参数一样),this 是在函数体被执行时创建的绑定。

对于典型的函数,this 的值是函数被访问的对象。换句话说,如果函数调用的形式是 obj.f(),那么 this 就指向 obj

严格模式下:
如果函数在没有被任何东西访问的情况下被调用,this 将是 undefined。

非严格模式下:
如果一个函数被调用时 this 被设置为 undefined 或 null,则this 会被替换为globalThis;
如果函数被调用时 this 被设置为一个原始值,this 会被替换为原始值的包装对象。

function bar() {console.log(Object.prototype.toString.call(this));
}bar.call(7); // [object Number]
bar.call("foo"); // [object String]
bar.call(undefined); // [object Window]

(2)全局上下文

在脚本的顶层,无论是否在严格模式下,this 会指向globalThis。如果源代码放在 HTML 的<script>元素内并作为脚本执行,则this === window

如果源代码作为模块加载(对于 HTML,这意味着在 <script> 标签中添加 type="module"),在顶层,this 总是 undefined

如果源代码使用eval()执行,this 与直接调用eval() 的闭合上下文相同,或者与间接调用 eval 的 globalThis(就像它在单独的全局脚本中运行一样)相同。

bind():

调用f.bind(someObj)会创建一个新函数,这个新函数具有与 f 相同的函数体和作用域,但 this 的值永久绑定(一旦绑定,后续再次绑定到其他对象的操作将会被忽略,绑定不生效但入参生效)到 bind 的第一个参数,无论函数如何被调用。调用绑定函数通常会执行其所包装的函数,也称为目标函数(target function)。绑定函数将绑定时传入的参数(包括 this 的值和前几个参数)提前存储为其内部状态,而不是等到实际调用时才传入。

"use strict"; // 防止 `this` 被封装到到包装对象中function log(...args) {console.log(this, ...args);
}
const boundLog = log.bind("this value", 1, 2);
const boundLog2 = boundLog.bind("new this value", 3, 4);
boundLog2(5, 6); // "this value", 1, 2, 3, 4, 5, 6

用法:其中arg1,arg2......可选,

bind(thisArg)
bind(thisArg, arg1)
bind(thisArg, arg1, arg2)
bind(thisArg, arg1, arg2, /* …, */ argN)

手写实现

Function.prototype.myBind = function () {const _this= thisconst args = Array.prototype.slice.call(arguments)const newThis = args.shift()return function () {return _this.apply(newThis, args)}
}

apply():

        通常情况下,在调用函数时,函数内部的this的值是访问该函数的对象。使用 apply(),你可以在调用现有函数时将任意值分配给 this,而无需先将函数作为属性附加到对象上。
        可以使用任何类数组对象作为第二个参数。实际上,这意味着它需要具有 length 属性,并且整数(“索引”)属性的范围在 (0..length - 1) 之间。像 { 'length': 2, '0': 'eat', '1': 'bananas' }这样的对象或['a','b']这样的数组甚至直接使用arguments,当然还可以使用剩余参数或者展开运算符。
        一般而言,fn.apply(null, args) 等同于使用参数展开语法的 fn(...args),只是在前者的情况下,args 期望是类数组对象,而在后者的情况下,args 期望是可迭代对象。

用法如下:

apply(thisArg)
apply(thisArg, argsArray)

手写实现

Function.prototype.myApply = function (context, args) {context = context || windowargs = [...args]const fn = Symbol()context[fn] = thisconst result = context[fn](...args)delete context[fn]return result
}

call():

功能与apply一致,只不过传参不同,函数的参数以列表的形式逐个传递给 call()的。

function greet() {console.log(this.animal, "的睡眠时间一般在", this.sleepDuration, "之间");
}const obj = {animal: "猫",sleepDuration: "12 到 16 小时",
};greet.call(obj); // 猫 的睡眠时间一般在 12 到 16 小时 之间

用法:

call(thisArg)
call(thisArg, arg1)
call(thisArg, arg1, arg2)
call(thisArg, arg1, arg2, /* …, */ argN)

 如果省略第一个 thisArg 参数,则默认为 undefined。在非严格模式下,this 值将被替换为全局对象globalThis。

 手写实现

Function.prototype.myCall = function (context) {context = context || windowconst arg = [...arguments].slice(1)const fn = Symbol()context[fn] = thisconst result = context[fn](...arg)delete context[fn]return result
}

bind()、apply()、bind()三者的异同

(1)相同点 
        bind、call、apply都能为函数内部的this分配指定值。 第一个参数均为this的目标值。均可以利用后续参数向目标函数传参。
(2)不同点
        call和bind传参相同,均是以此传入多个参数。apply只有两个参数,第二个参数为数组或类数组。call和apply均是直接调用目标函数,而bind方法不会立即调用函数,而是返回一个修改this后的新函数。
(3)使用场景 
        call函数的使用多用于类的继承。
        apply函数可配合Math.max()用于计算数组最大值等。
        bind函数可用于函数内部有定时器,改变定时器内部的this指向。

4.闭包

概念:在 JS 中,根据词法作用域的规则,内部函数总是可以访问其外部函数中声明的变量。当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了。但是内部函数引用外部函数的变量依然保存在内存中,就把这些变量的集合称为闭包。简单而言,闭包是一个函数,其有权访问其词法作用域内部的变量即使该函数在词法作用域外部被调用。

柯里化

在JavaScript中,函数柯里化是一种将多个参数的函数转变为一系列接受单一参数的函数的过程。这种转变过程可通过闭包和递归的方式实现。利用闭包,可以形成一个不销毁的私有作用域,把预先处理的内容都存在这个不销毁的作用域里面。

function multiply(a) {return function executeMultiply(b) {return a * b;}
}
const double = multiply(2);
double(3); // => 6
double(5); // => 10
const triple = multiply(3);
triple(4); // => 12

相关文章:

【JavaScript】原型链/作用域/this指针/闭包

1.原型链 参考资料&#xff1a;Annotated ES5 ECMAScript起初并不支持如C、Smalltalk 或 Java 中“类”的形式创建对象&#xff0c;而是通过字面量表示法或者构造函数创建对象。每个构造函数都是一个具有名为“prototype”的属性的函数&#xff0c;该属性用于实现基于原型的继…...

Python的MATLAB使用

Python和MATLAB是两种不同的编程语言&#xff0c;它们各自拥有不同的生态系统和库。然而&#xff0c;你可以在Python中使用一些方法来实现与MATLAB类似的功能。以下是一些方法和库&#xff0c;可以帮助你在Python中实现MATLAB风格的编程&#xff1a; 1. NumPy: NumPy是Python中…...

文件输入/输出流(I/O)

文章目录 前言一、文件输入\输出流是什么&#xff1f;二、使用方法 1.FileInputStream与FileOutputStream类2.FileReader与FileWriter类总结 前言 对于文章I/O(输入/输出流的概述)&#xff0c;有了下文。这篇文章将具体详细展述如何向磁盘文件中输入数据&#xff0c;或者读取磁…...

docker,schedule job和environment variables三者的含义与区别

这三个概念在软件开发和部署中扮演着不同的角色&#xff1a; Docker一般长这样&#xff1a;superlifestyle/sscp-api Schedule Job一般长这样&#xff1a;recorrect_ocr_receipt_status 、Sync2D365 Environment Variables一般长这样&#xff1a;D365_BATCH_OPERATION_SIZE ima…...

90天玩转Python—16—基础知识篇:面向对象知识详解

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…...

python 标准库之openpyxl的常规操作

目录 openpyxl&#xff08;Excel文件处理模块&#xff09; 读sheet 读sheet中单元格 合并单元格 openpyxl模块基本用法 安装方法 基本使用 读取Excel文档 &#xff08;一&#xff09;获取工作表 &#xff08;二&#xff09;获取单元格 &#xff08;三&#xff09;获取…...

90天玩转Python—12—基础知识篇:Python自动化操作Email:发送邮件、收邮件与邮箱客户端操作全解析

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…...

利用lidar_align来进行lidar和imu标定

文章目录 下载并安装lidar_align安装nlopt迁移NLOPTConfig.cmake修改loader.cpp文件编译并运行 下载并安装lidar_align mkdir -p lidar_align/src cd lidar_align/src git clone https://github.com/ethz-asl/lidar_align.git安装nlopt git clone http://github.com/steven…...

牛客NC93 设计LRU缓存结构【hard 链表,Map Java】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/5dfded165916435d9defb053c63f1e84 思路 双向链表map最新的数据放头结点&#xff0c;尾节点放最老的数据&#xff0c;没次移除尾巴节点本地考察链表的新增&#xff0c;删除&#xff0c;移动节点参考答案Java im…...

机器学习和深度学习 -- 李宏毅(笔记与个人理解1-6)

机器学习和深度学习教程 – 李宏毅&#xff08;笔记与个人理解&#xff09; day1 课程内容 什么是机器学习 找函数关键技术&#xff08;深度学习&#xff09; 函数 – 类神经网络来表示 &#xff1b;输入输出可以是 向量或者矩阵等如何找到函数&#xff1a; supervised Lear…...

低功耗全极霍尔开关芯片 D02,磁性开关点精确,对工艺和温度变化不敏感

1、概述 D02 是一款低功耗全极霍尔开关&#xff0c;用于检测施加的磁通量密度&#xff0c;并提供一个数字输出&#xff0c;该输出指示所感测磁通量幅度的当前状态。这些应用的一个例子是翻盖手机中的 ON/OFF 开关。微功耗设计特别适合电池供电系统&#xff0c;如手机或笔记本电…...

初识--数据结构

什么是数据结构&#xff1f;我们为什么要学习数据结构呢....一系列的问题就促使我们不得不了解数据结构。我们不禁要问了&#xff0c;学习C语言不就够了吗&#xff1f;为什么还要学习数据结构呢&#xff1f;这是因为&#xff1a;数据结构能够解决C语言解决不了的问题&#xff0…...

人工智能前沿成科技竞争新高地

以下文章来源&#xff1a;经济参考报 近日&#xff0c;首届中国具身智能大会&#xff08;CEAI 2024&#xff09;在上海举行。作为人工智能领域的前沿热点&#xff0c;具身智能正逐步走进现实&#xff0c;成为当前全球科技竞争的新高地、未来产业的新赛道、经济发展的新引擎。 “…...

【算法刷题day23】Leetcode:669. 修剪二叉搜索树、108. 将有序数组转换为二叉搜索树、538. 把二叉搜索树转换为累加树

文章目录 Leetcode 669. 修剪二叉搜索树解题思路代码总结 Leetcode 108. 将有序数组转换为二叉搜索树解题思路代码总结 Leetcode 538. 把二叉搜索树转换为累加树解题思路代码总结 草稿图网站 java的Deque Leetcode 669. 修剪二叉搜索树 题目&#xff1a;669. 修剪二叉搜索树 解…...

设计一个会议管理系统100问?

会议管理系统的基本功能有哪些&#xff1f;如何确保会议管理系统的安全性&#xff1f;会议管理系统可以支持多少种不同类型的会议&#xff1f;是否有权限管理功能&#xff1f;是否支持会议室预订功能&#xff1f;会议管理系统可以导入外部参与者信息吗&#xff1f;是否支持多种…...

一文搞懂BI、ERP、MES、SCM、PLM、CRM、WMS、APS、SCADA、QMS

在企业信息化数字化过程中我们经常遇到很多系统&#xff0c;比如&#xff1a;MES、ERP、SCM、WMS、APS、SCADA、PLM、QMS、CRM、EAM、BI&#xff0c;这些都是什么系统&#xff1f;有什么功能和作用&#xff1f;它们之间的关系是怎样的&#xff1f; 今天就一文简单分享。 术语 …...

全量知识系统 程序详细设计 之 先验逻辑-实现:从“平凡”回到“平凡” (QA 百度搜索)

Q1. 思考&#xff1a;数学中的平凡&#xff0c;和程序中的平凡&#xff08;比如POJO&#xff09;、语言中的平凡&#xff08;比如纯文本&#xff09;&#xff0c;数据中的平凡&#xff08;比如 Number&#xff09;。因为我设计中的全知系统将设计的三个方面刻画为语言设计、程序…...

注解(Annotation) --java学习笔记

注解 就是Java代码里的特殊标记&#xff0c;比如:Override、Test等&#xff0c;作用是:让其他程序根据注解信息来决定怎么执行该程序注意:注解可以用在类上、构造器上、方法上、成员变量上、参数上、等位置处 自定义注解 就是自己定义注解 自定义注解到底该怎么写&#xff1a…...

uniapp 小程序获取WiFi列表

<template><view ><button click"getWifiList">获取WiFi列表</button><scroll-view:scroll-top"scrollTop"scroll-yclass"content-pop"><viewclass"itemInfo"v-for"(item, index) in wifiList&…...

数据可视化-ECharts Html项目实战(11)

在之前的文章中&#xff0c;我们学习了如何在ECharts中特殊图表的双y图以及自定义形状词云图。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢。 数据可视化-ECh…...

【MySQL数据库 | 第二十四篇】Limit语句的性能问题和调优策略

前言&#xff1a; MySQL作为最流行的关系型数据库管理系统之一&#xff0c;被广泛应用于各种规模和类型的应用程序中。其强大的功能和灵活的查询语言使得开发人员能够高效地执行各种数据操作和分析。 然而&#xff0c;在处理大量数据或复杂查询时&#xff0c;一些开发人员可能…...

【数据结构】两两交换链表 复制带随机指针的链表

问题描述1 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 求解 使用一个栈S来存储相邻两个节点即可 /*** Definition for…...

网络安全流量平台_优缺点分析

FlowShadow&#xff08;流影&#xff09;&#xff0c;Ntm&#xff08;派网&#xff09;&#xff0c;Elastiflow。 Arkimesuricata&#xff0c;QNSMsuricata&#xff0c;Malcolm套件。 Malcolm套件优点&#xff1a;支持文件还原反病毒引擎&#xff08;clamav/yara&#xff09;…...

【c语言】自定义类型:结构体详解

目录 自定义类型&#xff1a;结构体 结构体类型的声明 结构体变量的创建和初始化 结构的特殊声明 结构的自引用 结构体内存对齐 对其规则 为什么存在内存对齐&#xff1f; 修改默认对⻬数 结构体传参 结构体实现位段 位段的内存分配 位段的跨平台问题 位段的应用…...

利用AbortController,取消正在发送的请求

参考文章&#xff1a;https://blog.csdn.net/qq_45560350/article/details/130588101 解决问题&#xff1a;再图层中点击仓库的时候&#xff0c;点击后又取消掉&#xff0c;我们希望这个请求可以被取消掉&#xff0c;我们口可以利用AbortController控制器对象 实操&#xff1a…...

dockerhub右键快速搜索脚本

Chrome 浏览器扩展的后台脚本&#xff0c;用于创建右键菜单项&#xff0c;并根据用户的操作在新的标签页中打开 Docker Hub 网站或者进行搜索。 // 创建右键菜单项&#xff0c;用于打开 Docker Hub 网站 chrome.contextMenus.create({id: search-home, // 菜单项的唯一标识符t…...

类似微信的以文搜图功能实现

通过PaddleOCR识别图片中的文字&#xff0c;将识别结果报存到es中&#xff0c;利用es查询语句返回结果图片。 技术逻辑 PaddleOCR部署、es部署创建mapping将PaddleOCR识别结果保存至es通过查询&#xff0c;返回结果 前期准备 PaddleOCR、es部署请参考https://blog.csdn.net…...

Android 13.0 Launcher3定制化之最近任务的全部清除由左边移到下边显示

1.概述 在最近13.0的系统rom产品开发中,在Launcher3的定制化开发中,在最近任务列表中,发现点击recents最近任务键后 显示的全部清除按键在左边 由于是横屏的产品显示在左边不太合理 所以要求显示在下边比较合理,所以要从Launcher3的显示流程来解决这个问题 2. 最近任务全…...

成都数字产业园落地全生命周期服务方案, 让企业对成都发展更有信心

国际数字影像产业园&#xff0c;作为现代科技与文化创意的交汇点&#xff0c;致力于为企业落地全生命周期的服务方案&#xff0c;让企业对成都发展更有信心。该服务模式贯穿了企业的初创期到成熟期的各个阶段&#xff0c;确保每一家入驻园区的企业都能得到全方位的支持和帮助。…...

SpringBoot实现RabbitMQ的通配符交换机(SpringAMQP 实现Topic交换机)

文章目录 pomyml生产者消费者 Topic类型的Exchange与Direct相比&#xff0c;都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符&#xff01; Routingkey 一般都是有一个或多个单词组成&#xff0c;多个单词…...