ES6:Generator函数详解

ES6:Generator函数详解

  • 1、 概念
  • 2、yield表达式
    • 2.1 yield 语句与 return 语句区别
    • 2.2 Generator函数不加yield语句,这时变成了一个单纯的暂缓执行函数
    • 2.3 yield 表达式只能用在 Generator 函数里面,用在其它地方都会报错
    • 2.4 yield 表达式如果用在另一个表达式中,必须放在圆括号里面
    • 2.5 yield 表达式用作参数或放在赋值表达式的右边,可以不加括号
  • 3、与 Iterator 接口的关系
  • 4、next() 方法的参数
  • 5、for...of循环
  • 6、Generator.prototype.throw()
  • 7、Generator.prototype.return()
  • 8、yield*表达式
  • 9、Generator函数应用举例
    • 9.1 利用 Generator 函数和 for...of 循环实现斐波那契数列
    • 9.2 异步操作的同步化表达
    • 9.3 逐行读取文本文件
    • 9.4 控制流管理
    • 9.5 Genarator 对任意对象部署Iterator接口
    • 9.6 Genarator 对数组部署Iterator接口
  • 10、promise、generator和aysnc/await区别
    • 10.1 promise
    • 10.2 Generator
    • 10.3 async/await

1、 概念

Generator函数式ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。对于Generator函数有多种理解角度。
从语法上:可以把它理解成一个状态机,封装了多个内部状态;
从形式上:Generator 函数是一个普通函数,但是有两个特征:一是function命令与函数名之间有一个星号*;二是函数体内部使用yield语句定义不同的内部状态。

// 传统函数
function fn() {return 'hello world'
}
fn()  // 'hello world',一旦调用立即执行// Generator函数
function* helloWorldGenerator () {yield 'hello'yield 'world'return 'ending'
}const hw = helloWorldGenerator()  // 调用 Generator函数,函数并没有执行,返回的是一个Iterator对象
console.log(hw.next())  // {value: 'hello', done: false},value 表示返回值,done 表示遍历还没有结束
console.log(hw.next())  // {value: 'world', done: false},value 表示返回值,done 表示遍历还没有结束
console.log(hw.next())  // {value: 'ending', done: true},value 表示返回值,done 表示遍历还没有结束
console.log(hw.next())  // {value: undefined, done: true},value 表示返回值,done 表示遍历结束

上面的代码中可以看到传统函数和Generator函数的运行是完全不同的,传统函数调用后立即执行并输出了返回值;Generator函数则没有执行而是返回一个Iterator对象,并通过调用Iterator对象的next方法来遍历,每次调用Iterator对象的next方法时,内部的指针就会从函数的头部或上一次停下来的地方开始执行,直到遇到下一个 yield 表达式或return语句暂停。换句话说,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而 next方法可以恢复执行。
执行过程如下:

  • 第1次调用,Generator 函数开始执行,直到遇到第一条 yield 语句为止。next 方法返回一个对象,它的 value 属性就是当前 yield 语句的值 hellodone 属性的值 false 表示遍历还没有结束。
  • 第2次调用,Generator 函数从上次 yield 语句停下的地方,一直执行到下一条 yield 语句。next 方法返回的对象的 value 属性就是当前 yield 语句的值 worlddone 属性的值false 表示遍历还没有结束。
  • 第 3 次调用,Generator 函数从上次 yield 语句停下的地方,一直执行到 return 语句(如果没有 return 语句,就执行到函数结束)。next 方法返回的对象的 value 属性就是紧跟在return 语句后面的表达式的值(如果没有 return 语句,则 value 属性的值为 undefined),done 属性的值 true 表示遍历已经结束。
  • 第 4 次调用,此时 Generator 函数已经运行完毕,next 方法返回的对象的 value 属性为undefineddone 属性为 true。以后再调用 next 方法,返回的都是这个值。

2、yield表达式

由于 Generator 函数返回的遍历器对象只有调用 next 方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield 语句就是暂停标志。
遍历器对象的 next 方法的运行逻辑如下。
1.遇到 yield 语句就暂停执行后面的操作,并将紧跟在 yield 后的表达式的值作为返回的对象的 value 属性值。
2.下一次调用 next 方法时再继续往下执行,直到遇到下一条 yield 语句。
3.如果没有再遇到新的 yield 语句,就一直运行到函数结束,直到 return 语句为止,并将 return 语句后面的表达式的值作为返回对象的value 属性值。
4.如果该函数没有 return 语句,则返回对象的 value 属性值为undefined

注意:只有调用next方法且内部指针指向该语句时才会执行yield语句后面的表达式,因此,等于为JavaScript提供了手动的“惰性求值”的语法功能。

function* gen() {yield 123 + 456;
}

上面的代码中,yield 后面的表达式 123 + 456 不会立即求值,只会在 next 方法将指针移到这一句时才求值。

2.1 yield 语句与 return 语句区别

yield 语句与 return 语句既有相似之处,又有区别。相似之处在于都能返回紧跟在语句后的表达式的值。区别在于每次遇到 vield 函数暂停执行,下一次会从该位置继续向后执行而 return 语句不具备位置记忆的功能。一个函数里面只能执行一次(或者说一条) return语句,但是可以执行多次(或者说多条) yield 语句。正常函数只能返回一个值,因为只能执行一次 return 语句;Generator 函数可以返回一系列的值,因为可以有任意多条 yield 语句。从另一个角度看,也可以说 Generator 生成了一系列的值,这也就是其名称的来历(在英语中generator”这个词是“生成器”的意思)。

2.2 Generator函数不加yield语句,这时变成了一个单纯的暂缓执行函数

function* f () {console.log('执行了')
}
var generator = f()
setTimeout(function () {generator.next()
}, 2000)

上面的代码中,函数 f 如果是普通函数,在为变量 generator 赋值时就会执行。但是函数 f是一个 Generator 函数,于是就变成只有调用 next 方法时才会执行。

2.3 yield 表达式只能用在 Generator 函数里面,用在其它地方都会报错

{(function (){yield 1;})()// SyntaxError: Unexpected number// 在一个普通函数中使用yield表达式,结果产生一个句法错误
}

2.4 yield 表达式如果用在另一个表达式中,必须放在圆括号里面

{function* demo() {console.log('Hello' + yield); // SyntaxErrorconsole.log('Hello' + yield 123); // SyntaxErrorconsole.log('Hello' + (yield)); // OKconsole.log('Hello' + (yield 123)); // OK}
}

2.5 yield 表达式用作参数或放在赋值表达式的右边,可以不加括号

{function* demo() {foo(yield 'a', yield 'b'); // OKlet input = yield; // OK}
}

3、与 Iterator 接口的关系

任意一个对象的 Symbol.iterator 方法等于该对象的遍历器对象生成函数,调用该函数会返回该对象的一个遍历器对象。
由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的Symbol.iterator 属性,从而使得该对象具有 Iterator 接口。

var myIterable = {}
myIterable[Symbol.iterator] = function* () {yield 1yield 2yield 3
}for(let value of myIterable) {console.log(value)}// 1// 2// 3
[...myIterable]  // [1, 2, 3]

上面的代码中,Generator 函数赋值给 Symbol.iterator 属性,从而使得 myIterable对象具有了 Iterator 接口,可以被...运算符遍历。

4、next() 方法的参数

yield 语句本身没有返回值,或者说总是返回 undefinednext 方法可以带有一个参数,该参数会被当作上一条 yield 语句的返回值。

function* f () {for (var i = 0; true; i++) {var reset = yield iif (reset) {console.log('执行了')i = -1}}
}
var g = f()
g.next()  // {value: 0, done: false}
g.next()  // {value: 1, done: false}
g.next(true)  // {value: 0, done: false}

上面的代码先定义了一个可以无限运行的 Generator 函数 f,如果 next 方法没有参数,每次运行到 yield 语句时,变量 reset 的值总是 undefined。当next 方法带有一个参数 true时,当前的变量 reset 就被重置为这个参数(即 true),因而 i 会等于-1,下一轮循环就从-1开始递增。

这个功能有很重要的语法意义。Generator 函数从暂停状态到恢复运行,其上下文状态(context)是不变的。通过 next 方法的参数就有办法在Generator 函数开始运行后继续向函数本内部注入值。也就是说,可以在 Generator 函数运行的不同阶段从外部向内部注入不同的值,从而调整函数行为。
再看一个例子。

function* foo (x) {var y = 2 * (yield (x + 1))var z = yield (y / 3)return (x + y + z)
}var a = foo(5)
a.next()  // 首次调用next,函数只会执行到 “yield(5+1)” 暂停,并返回 {value: 6, done: false}
a.next()  // 第二次调用next,没有传递参数,所以 y的值是undefined,那么 y/3 当然是一个NaN,所以应该返回 {value: NaN, done: false}
a.next()  // 同样的道理,z也是undefined,6 + undefined + undefined = NaN,返回 {value: NaN, done: true}var b = foo(5)
b.next()  // 正常的运算应该是先执行圆括号内的计算,再去乘以2,由于圆括号内被 yield 返回 5 + 1 的结果并暂停,所以返回{value: 6, done: false}
b.next(12)  // 上次是在圆括号内部暂停的,所以第二次调用 next方法应该从圆括号里面开始,就变成了 let y = 2 * (12),y被赋值为24,所以第二次返回的应该是 24/3的结果 {value: 8, done: false}
b.next(13)  // 参数2被赋值给了 z,最终 x + y + z = 5 + 24+ 13 = 42,返回 {value: 42, done: true}

5、for…of循环

for...of 循环可以自动遍历 Generator 函数生成的 Iterator 对象,且此时不再需要调用next 方法。

function* foo () {yield 1yield 2yield 3yield 4yield 5return 6
}
for (let v of foo()) {console.log(v)
}
// 1 2 3 4 5

上面的代码使用 for...of 循环依次显示 5条 yield 语句的值。
注意:一旦 next 方法的返回对象的 done 属性为 true,for…of 循环就会终止,且不包含该返回对象,所以上面的 return 语句返回的 6 不包括在 for…of 循环中。

6、Generator.prototype.throw()

Generator 函数返回的遍历器对象都有一个 throw 方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获。

var g = function* () {try (yield;} catch (e) {console.log('内部捕获’,e);}
}var i=g();
i.next();try {i.throw('a');i.throw('b');
} catch (e) {console.log('外部捕获’,e);
}
//内部捕获a
// 外部捕获b

上面的代码中,遍历器对象 i 连续抛出两个错误。第一个错误被 Generator 函数体内的catch 语句捕获。i 第二次抛出错误,由于 Generator 函数内部的 catch 语句已经执行过了,不会再捕捉到这个错误了,所以这个错误就被抛出了 Generator 函数体,被函数体外的 catch语句捕获。

7、Generator.prototype.return()

Generator 函数返回的遍历器对象还有一个 return 方法,可以返回给定的值,并终结Generator 函数的遍历。

function* gen() {yield 1;yield 2;yield 3;
}
var g = gen();
g.next ()  // { value: 1, done: false }
g.return('foo')  // { value:"foo",done: true }
g.next()  // { value: undefined, done: true }

上面的代码中,遍历器对象 g 调用 return 方法后,返回值的 value 属性就是 return方法的参数 foo。同时,Generator 函数的遍历终止,返回值的 done 属性为 true,以后再调用 next 方法,done 属性总是返回 true
如果 return 方法调用时不提供参数,则返回值的 vaule 属性为 undefined

function* gen() {yield 1;yield 2;yield 3;
}
var g = gen();
g.next()  // { value: 1,done: false }
g.return()  // { value: undefined,done: true }

8、yield*表达式

如果在 Generator函数内部调用另一个 Generator 函数,默认情况下是没有效果的。

function* foo() {yield 'a';yield'b';
}
function* bar() {yield'x';foo();yield 'y';
}
for (let v of bar()){console.log(v);
}
//"x"
//"y"

上面的代码中,foobar 都是 Generator 函数,在 bar 里面调用 foo 是不会有效果的。

这时就需要用到 yield*语句,用来在一个 Generator 函数里面执行另一个 Generator 函数。

function* bar() {yield 'x';yield* foo();yield'y';
}
// 等同于
function* bar() [yield 'x';yield 'a';yield 'b';yield 'y';
}
// 等同于
function* bar() {yield 'x';for (let v of foo()) {yield v;}yield 'y';
}
for (let v of bar()) {console.log(v);
}
// 'x';
// 'a';
// 'b';
// 'y';

9、Generator函数应用举例

9.1 利用 Generator 函数和 for…of 循环实现斐波那契数列

function* fibonacci() {let [prev,curr] = [01];for (;;) {[prev, curr] = [curr, prev + currl;yield curr;}
}
for (let n of fibonacci()) {if (n > 1000) break;console.log(n);
}
// 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

9.2 异步操作的同步化表达

Generator 函数的暂停执行的效果,意味着可以把异步操作写在yield表达式里面,等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了,因为异步操作的后续操作可以放在yield表达式下面,反正要等到调用next方法时再执行。所以,Generator 函数的一个重要实际意义就是用来处理异步操作,改写回调函数。

function* main() {var result = yield request('http://some.url');var resp = JSON.parse(result);console.log(resp.value);
}
function request(url) {makeAjaxCall(url, function(response){it.next(response);});
}
var it = main();
it.next();

上面代码的main函数,就是通过 Ajax 操作获取数据。可以看到,除了多了一个yield,它几乎与同步操作的写法完全一样。
注意,makeAjaxCall函数中的next方法,必须加上response参数,因为yield表达式,本身是没有值的,总是等于undefined

9.3 逐行读取文本文件

function* numbers() {let file = new FileReader("numbers.txt");try {while(!file.eof) {yield parseInt(file.readLine()10);}} finally {file.close();}
}

上面的代码打开文本文件,使用 yield 语句可以手动逐行读取文件。

9.4 控制流管理

如一个多步操作非常耗时,采用回调的话:

step1(function (value1) {step2(value1, function(value2) {step3(value2, function(value3) {step4(value3, function(value4) {// Do something with value4});});});
});

采用Promise改写上面的代码如下:

Promise.resolve(step1).then(step2).then(step3).then(step4).then(function (value4) {// Do something with value4}, function (error) {// Handle any error from step1 through step4}).done();

上面的代码已经把回调函数改成了直线执行的形式,但是加入了大量 Promise 的语法。Generator 函数可以进一步改善代码运行流程。

function* longRunningTask(valuel) {try {var value2 = yield stepl(valuel);var value3 = yield step2(value2);var value4 = yield step3(value3);var value5 = yield step4(value4);// Do something with value4} catch (e) {// Handle any error from stepl through step4}
}

9.5 Genarator 对任意对象部署Iterator接口

function* deployObjectInterface(obj){let keys = Object.keys(obj);for(let i=0; i<keys.length; i++){let key = keys[i];yield [key, obj[key]];}
}
let obj = {name:"jow", age:21 };
for(let[key, value] of deployObjectInterface(obj)){console.log(key, value); 
}
// name jow
// age 21

9.6 Genarator 对数组部署Iterator接口

function* deployArrayInterface(arr){var nextIndex = 0;while(nextIndex < arr.length){yield arr[nextIndex++];}
}
var arr = deployArrayInterface(['name', 'age']);console.log(arr.next());       // {value: "name", done: false}
console.log(arr.next().value); // name
console.log(arr.next().done);  // falseconsole.log(arr.next().value); // age
console.log(arr.next().done);  // trueconsole.log(arr.next().value); // undefined
console.log(arr.next().done);  // true

10、promise、generator和aysnc/await区别

三者都是异步编程的解决方案,不同的是,promise为较早出来的,其次generator,最后为async/await,三者象征了前端进行解决异步编程的进化路程。

10.1 promise

 promise比较简单,也是最常用的,主要就是将原来用回调函数异步编程的方法转成relsove和reject触发事件;对象内含有四个方法,then()异步请求成功后catch()异步请求错误的回调方法finally()请求之后无论是什么状态都会执行resolve()将现有对象转换为Promise对象all()此方法用于将多个Promise实例包装成一个新的promise实例。race()也是将多个Promise实例包装成一个新的promise实例reject()返回一个状态为Rejected的新Promise实例。优点:让回调函数变成了规范的链式写法,程序流程可以看的很清楚缺点:编写的难度比传统写法高,阅读代码也不是一眼可以看懂

10.2 Generator

generator是一个迭代生成器,其返回值为迭代器(lterator),ES6标准引入的新的数据类型,主要用于异步编程,它借鉴于Python中的generator概念和语法;generator函数内有两个重要方法,1 yield表达式 2.next()Generator 函数是分段执行的,yield表达式是暂停执行的标记,而 next方法可以恢复执行优点:1.利用循环,每调用一次,就使用一次,不占内存空间 2.打破了普通函数执行的完整性
缺点: 需要用next()方法手动调用,直接调用返回无效iterator 2.

10.3 async/await

   
async:异步函数
await:同步操作es7中提出来的异步解决方法,是目前解决异步编程终极解决方案,以promise为基础,其实也就是generator的高级语法糖,本身自己就相当于一个迭代生成器(状态机),它并不需要手动通过next()来调用自己,与普通函数一样async就相当于generator函数中的*,await相当于yield,async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
function getSomething() {return "something";
}async function testAsync() {return Promise.resolve("hello async");
}async function test() {//await是在等待一个async函数完成const v1 = await getSomething();//await后面不仅可以接Promise,还可以接普通函数或者直接量const v2 = await testAsync();console.log(v1, v2);
}

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

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

相关文章

MySQL~多表查询

一、多表查询 查询语法&#xff1a; select列名列表 from表名列表 where.... 1、准备sql 创建部门表 CREATE TABLE dept(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20) ); INSERT INTO dept (NAME) VALUES (开发部),(市场部),(财务部); 创建员工表 CREATE TABL…

Flink(十三)Flink 的table api与sql的基本概念、通用api介绍及入门示例

Flink 系列文章 Flink&#xff08;一&#xff09;1.12.7或1.13.5详细介绍及本地安装部署、验证 Flink&#xff08;二&#xff09;1.13.5二种部署方式(Standalone、Standalone HA )、四种提交任务方式&#xff08;前两种及session和per-job&#xff09;验证详细步骤 Flink&…

android framework车载桌面CarLauncher的TaskView详细源码分析

1、构建相关的TaskView&#xff0c;装载到对应的ViewGroup b站免费视频教程讲解&#xff1a; https://www.bilibili.com/video/BV1wj411o7A9/ //packages/apps/Car/Launcher/src/com/android/car/carlauncher/CarLauncher.java void onCreate() { //ignoresetContentView(R.…

macos下安装john the ripper并配置zip2john+破解加密zip文件

为了破解加密的zip文件&#xff0c;需要用到john进行爆破密码。 1、首先使用homebrew安装john&#xff0c;可以安装它的增强版john-jumbo: brew install john-jumbo 2、安装后可以使用 john 命令验证&#xff1a; john 3、配置zip2john的环境——.zshrc下&#xff0c;&#x…

城市气象数据可视化:洞察气候变化,构建智慧城市

随着城市化进程的加速&#xff0c;城市气象数据的采集和分析变得越来越重要。气象数据不仅影响着人们的生活和出行&#xff0c;还与城市的发展和规划息息相关。在数字化时代&#xff0c;如何将城市中各个气象数据进行可视化&#xff0c;让复杂的数据变得简单易懂&#xff0c;成…

【JavaEE初阶】HTTP请求的构造及HTTPS

文章目录 1.HTTP请求的构造1.1 from表单请求构造1.2 ajax构造HTTP请求1.3 Postman的使用 2. HTTPS2.1 什么是HTTPS?2.2 HTTPS中的加密机制(SSL/TLS)2.2.1 HTTP的安全问题2.2.2 对称加密2.2.3 非对称加密2.2.3 中间人问题2.2.5 证书 1.HTTP请求的构造 常见的构造HTTP 请求的方…

名词性从句

文章目录 名词性从句的分类主语从句不确定的信息的主语从句形式主语 宾语从句that引导词可以省略宾语从句的否定 从句&#xff1a;(从句引导词主谓)从句指复合句中不能独立成句&#xff0c;但具有主语部分和谓语部分&#xff0c;有that、who、what、when、how等引导词引导的非主…

简单工厂模式——集中式工厂的实现

1、简介 1.1、概述 简单工厂模式并不属于GoF 23个经典设计模式&#xff0c;但通常将它作为学习其他工厂模式的基础&#xff0c;它的设计思想很简单&#xff0c;其基本流程如下&#xff1a; 首先将需要创建的各种不同对象的相关代码封装到不同的类中&#xff0c;这些类称为具体…

Pushgateway+Prometheus监控Flink

思路方案 FlinkMtrics->pushgateway->prometheus->grafnana->altermanager 方案 : Flink任务先将数据推到pushgateway。然后pushgateway将值推送到prometheus,最后grafana展示prometheus中的值, 去这个 https://prometheus.io/download/ 下载最新的 Prometheu…

【IDEA】idea不自动生成target

文章目录 1. 不生成target2. 仅部分文件不生成target2.1. 一般原因就是资源没有设置2.2. 配置编译src/main/java文件夹下的资源文件2.3. 清理缓存&#xff08;王炸&#xff09; 3. 参考资料 本文描述idea不生成target的几种情况以及处理方法 1. 不生成target 像下图这样根本就…

一篇文章搞定Java泛型

目录 介绍 优点 泛型类 语法定义 代码示例 泛型类注意事项 抽奖示例 泛型类派生子类 定义 代码示例 子类是泛型 子类不是泛型 泛型接口 定义 泛型方法 定义 代码示例 泛型方法与可变参数 泛型方法总结 ​编辑类型通配符 定义 代码示例 通配符的上限 定义 …

致敬图灵!HashData拥抱数据智能新时代!

图1&#xff1a;2023ACM中国图灵大会现场 生于1912年的艾伦图灵被称为“计算机科学之父”、“人工智能之父”。1966年&#xff0c;国际计算机协会&#xff08;ACM&#xff09;为了纪念这位卓越的科学家&#xff0c;设立了以其名字命名的ACM图灵奖&#xff0c;以表彰在计算机领…

入门redis你一定需要知道的命令

1、各种数据类型的特点 字符串(string)&#xff1a;普通字符串&#xff0c;Redis中最简单的数据类型 哈希(hash)&#xff1a;也叫散列&#xff0c;类似于Java中的HashMap结构 列表(list)&#xff1a;按照插入顺序排序&#xff0c;可以有重复元素&#xff0c;类似于Java中的Li…

nginx如何配置两个服务器的连接

nginx 中通过server_name listen的方式配置多个服务器 nginx配置两个站点的windows操作方法&#xff0c;双域名双站点

JavaWeb_LeadNews_Day4-阿里云内容安全, 雪花算法, app文章保存, 自媒体文章审核

JavaWeb_LeadNews_Day4-阿里云内容安全, 雪花算法, app文章保存, 自媒体文章审核 阿里云内容安全分布式主键策略-雪花算法app文章保存具体实现总结 自媒体文章审核提取内容和图片审核内容和图片保存app端文章Feign远程调用降级发布文章异步调用自管理敏感词图片文字识别入门集成…

【【51单片机11.0592晶振红外遥控】】

51单片机11.0592晶振红外遥控 红外遥控&#xff0c;51单片机完结 这是初步实现的架构 怎么实现内部的详细逻辑 我们用状态机的方法 0状态时一个空闲状态 当它接收到下降沿开始计时然后转为1状态 1状态下 寻找start 或者repeat的信号 再来下降沿读出定时器的值 如果是start 那…

UE4/5C++多线程插件制作(十八、Graph线程封装,以及宏的设置)

目录​​​​​​​ 什么是Graph线程? MTPThreadGraphManage.h MTPThreadInterface.h MTPThreadGraphManage.h MTPManage.cpp void FMTPThreadGraphManage::Wait(const FGraphEventRef& EventRef)</

QT 常用数据结构整理

目录 QString篇 QString篇 //初始化bool bOk false;QString str "sd";QString strTemp(str);str QString("%1,%2").arg("11").arg("-gg");qDebug()<<str;str.sprintf("%s %d","ni",1);qDebug()<<…

网安笔记2

一、实例对象 1.对象是单个实物的抽象&#xff0c;是一个容器&#xff0c;封装了属性和方法 2.构造函数&#xff0c;构造函数就是一个普通的函数&#xff0c;但具有自己的特征和用法。 var Vehicle function () { this.price 1000; }; 上面代码中&#xff0c;Ve…

前端(Electron Nodejs)如何读取本地配置文件

使用electron封装了前端界面之后&#xff0c;最终打包为一个客户端&#xff08;exe&#xff09;。但是&#xff0c;最近项目组内做CS&#xff08;c开发&#xff09;的&#xff0c;想把所有的配置都放进安装目录的配置文件中&#xff08;比如config.json&#xff09;。这做法&am…