0%

今天有个工作场景是一个注册函数需要执行一次注册任务, 但是该函数仅仅只能在初始化的时候执行一次注册任务, 即该函数只能执行一次.

如何实现这个逻辑?

1
2
3
4
5
6
7
8
9
10
def _register():
print("register ...")


_register()
_register()
_register()

# 多次调用也只能输出一次
>>> register ...

基于类的单例模式

… 略, 想起来再写

基于闭包

我们还可以使用闭包来实现这个逻辑.

维基百科的闭包解释

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是在支持头等函数的编程语言中实现词法绑定的一种技术。闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。环境里是若干对符号和值的对应关系,它既要包括约束变量(该函数内部绑定的符号),也要包括自由变量(在函数外部定义但在函数内被引用),有些函数也可能没有自由变量。闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行。捕捉时对于值的处理可以是值拷贝,也可以是名称引用,这通常由语言设计者决定,也可能由用户自行指定(如C++)。

看起来非常的绕, 笔者的简单理解就是函数打包了一份本地环境, 并且通常来将, 闭包的内部变量对于外界是完全隐藏的(但是也有办法访问到)

基于闭包实现上述逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def _register():

# 这里我们在函数内部定义了一个
# 内部变量, 表示该函数是否已经
# 执行过
_loaded = False

def _load():
# 这里写该函数的具体执行逻辑
print("fisrt run, loading ...")
print("loaded")
# 当逻辑被执行一次以后
# 我们需要将设置 _loaded = True
# 用来表示该函数已经被执行过一次
# nonlocal 表示该变量不是本地变量
nonlocal _loaded
_loaded = True

def _run():
if not _loaded:
_load()

return _run

这样我们就实现了一个只能执行一次的函数

执行

1
2
3
f = _register()
f()
f()

可以发现只执行了一次逻辑

1
2
fisrt run, loading ...
loaded

什么是setup语法糖

起初 Vue3.0 暴露变量必须 return 出来,template中才能使用;

现在只需在script标签中添加setup,组件只需引入不用注册,属性和方法也不用返回,也不用写setup函数,也不用写export default ,甚至是自定义指令也可以在我们的template中自动获得。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<my-component :num="num" @click="addNum" />
</template>

<script setup>
import { ref } from 'vue';
import MyComponent from './MyComponent .vue';

// 像在平常的setup中一样的写,但是不需要返回任何变量
const num= ref(0) //在此处定义的 num 可以直接使用
const addNum= () => { //函数也可以直接引用,不用在return中返回
num.value++
}
</script>

使用setup组件自动注册

script setup 中,引入的组件可以直接使用,无需再通过components进行注册,并且无法指定当前组件的名字,它会自动以文件名为主,也就是不用再写name属性了

1
2
3
4
5
6
7
<template>
<zi-hello></zi-hello>
</template>

<script setup>
import ziHello from './ziHello'
</script>

使用setup后新增API

因为没有了setup函数,那么propsemit怎么获取呢

setup script语法糖提供了新的API来供我们使用

defineProps

用来接收父组件传来的 props。示例:

父组件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div class="die">
<h3>我是父组件</h3>
<zi-hello :name="name"></zi-hello>
</div>
</template>

<script setup>
import ziHello from './ziHello'

import {ref} from 'vue'
let name = ref('赵小磊========')
</script>

子组件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
我是子组件{{name}} // 赵小磊========
</div>
</template>

<script setup>
import {defineProps} from 'vue'

defineProps({
name:{
type:String,
default:'我是默认值'
}
})
</script>

defineEmits

子组件向父组件事件传递。示例:

子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div>
我是子组件{{name}}
<button @click="ziupdata">按钮</button>
</div>
</template>

<script setup>
import {defineEmits} from 'vue'

//自定义函数,父组件可以触发
const em=defineEmits(['updata'])
const ziupdata=()=>{
em("updata",'我是子组件的值')
}

</script>

父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div class="die">
<h3>我是父组件</h3>
<zi-hello @updata="updata"></zi-hello>
</div>
</template>

<script setup>
import ziHello from './ziHello'

const updata = (data) => {
console.log(data); //我是子组件的值
}
</script>

defineExpose

组件暴露出自己的属性,在父组件中可以拿到。示例:

子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div>
我是子组件
</div>
</template>

<script setup>
import {defineExpose,reactive,ref} from 'vue'
let ziage=ref(18)
let ziname=reactive({
name:'赵小磊'
})
//暴露出去的变量
defineExpose({
ziage,
ziname
})
</script>

父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div class="die">
<h3 @click="isclick">我是父组件</h3>
<zi-hello ref="zihello"></zi-hello>
</div>
</template>

<script setup>
import ziHello from './ziHello'
import {ref} from 'vue'
const zihello = ref()

const isclick = () => {
console.log('接收ref暴漏出来的值',zihello.value.ziage)
console.log('接收reactive暴漏出来的值',zihello.value.ziname.name)
}
</script>

参考链接

https://www.jb51.net/article/231485.htm
https://v3.cn.vuejs.org/api/sfc-script-setup.html#%E4%BD%BF%E7%94%A8%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E4%BB%A4

常见错误解决方案

SyntaxError: Cannot use import statement outside a module

无法在模块外使用import

package.json添加"type":"modules"

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"

我收到这条报错的时候,命令行命令使用的是ts-node ./myscripts.ts,改用以下命令时,问题解决。

1
node --loader ts-node/esm ./my-script.ts

参考链接

https://cloud.tencent.com/developer/article/1805310

循环赋值

1
2
3
4
5
var arr1 = new Array(100);
for(var i=0;i<arr1.length;i++){
arr1[i] = i;
}
console.log(arr1);

push方法实现

1
2
3
4
5
var arr2 = new Array();
for(var i=0;i<100;i++){
arr2.push(i);
}
console.log(arr2);

while

1
2
3
4
5
6
7
var arr3 = new Array();
var i = 0;
while(i<100){
arr3.push(i);
i++;
}
console.log(arr3);

do while

1
2
3
4
5
6
7
8
var arr4 = new Array();
var i = 0;
do{
arr4.push(i);
i++;
}
while(i<100)
console.log(arr4);

Object.keys

1
2
3
4
5
6
var arr5 = Object.keys(Array.apply(null, {length:100})).map(function(item){

return +item;

});
console.log(arr5);

Array.from

1
2
var arr6 = Array.from({length:100}, (v,k) => k);
console.log(arr6);
1
2
var arr7 = Array.from(Array(100), (v,k) =>k);
console.log(arr7);

new Array(100).keys()

1
2
var arr8 = new Array(100).keys();
console.log(Array.from(arr8));

递归

1
2
3
4
5
6
7
8
9
10
var arr = [];
var i = 0;
function MakeArray(num){
if(i<num){
arr[i] = i++;
MakeArray(num);
}
return arr;
}
console.log(MakeArray(100));

new Array(100).toString()

1
2
3
4
var arr11 = new Array(100).toString().split(‘,‘).map(function(item,index){
return index;
});
console.log(arr11);

参考链接

https://www.cnblogs.com/fuzitu/p/10723869.html

前言

我们经常会遇到这样的麻烦事,多个函数按顺序执行,返回结果却不是我们预期的顺序,原因一般是由于异步操作引起的,所以呢,我们需要一种解决方案来处理这种问题,从而使得异步操作按照同步的方式来执行,这样我们就可以控制异步操作输出结果的顺序了

异步操作会带来什么问题

异步操作可能会许多的问题,下面是常见的两种

1.函数执行的结果并不是按照顺序返回

1
2
3
4
5
6
7
8
9
10
11
12
function fn1(){
console.log(111)
setTimeout(function(){
console.log('wait me 3000')
},3000)
}
function fn2(){
console.log(222)
}
fn1();
fn2();

1
2
3
4
//结果
//111
//222
//wait me 3000

上面的代码,如果你期待的结果是

1
2
3
//111
//wait me 3000
//222

那就错了,因为fn1函数里面还有一个函数setTimeout,这两个函数是异步执行的,而fn1fn2是同步执行的,先执行fn1再执行fn2,在执行fn1的时候打印结果111,三秒后再执行setTimeout,但是在这三秒之前已经执行完了fn2

2.在外部获取不到异步函数里的值

下面我们看一个最简单的例子,我的需求是要在fn1函数外面打印msg

1
2
3
4
5
6
function fn1(){
setTimeout(function(){
msg='wait me 3000';
},3000);
}
fn1();

那么怎么样才能获取到msg

使用回调函数

1
2
3
4
5
6
7
8
9
function fn1(callback){
setTimeout(function(){
msg='wait me 3000';
callback(msg);
},3000);
}
fn1(data=>{
console.log(data);//wait me 3000
});

使用Promise

1
2
3
4
5
6
7
8
9
10
11
function fn1(){
return new Promise(function(res,rej){
setTimeout(function(){
msg='wait me 3000';
res(msg);
},3000);
})
}
fn1().then(data=>{
console.log(data)
})

关于Promise的信息可以参考

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

async/await解决方案

async/await的作用就是使异步操作以同步的方式去执行

异步操作同步化?

可以使用Promise中的then()来实现,那么async/await与它之间有什么区别呢

1.async函数返回的是一个Promise对象

如果一个函数加了async关键词,这个函数又有返回值,在调用这个函数时,如果函数执行成功,内部会调用Promise.solve()方法返回一个Promise对象,如果函数执行出现异常,就会调用Promise.reject()方法返回一个promise对象

要想获取到async函数的执行结果,就要调用Promisethencatch来给它注册回调函数

1
2
3
4
async function fn(){
return '111'
}
console.log(fn());//Promise { '111' }

既然是Promise对象,因此可以使用then()获取返回的结果

1
2
3
4
5
6
async function fn(){
return '111'
}
fn().then(data=>{
console.log(data)//111
})

2.await

上面介绍了async的作用,一般情况下,asyncawait配合使用才能使异步操作同步化,await就是等待的意思,等待某一个函数执行完之后,后面的代码才能开始执行

1
2
3
4
5
6
7
8
9
10
11
12
13
function fn1(){
return new Promise(resolve=>{
setTimeout(function(){
msg='wait me 3000';
resolve(msg)
},3000);
});
}
async function asyncCall(){
var result=await fn1();
console.log(result);
}
asyncCall();

如果我们没有等待fn1执行完之后再打印result,那么有可能得到是undefined

总结

aysnc await可以让我们以同步的方式编写异步代码

在很多的时候,我们是希望按照同步的方式来获得异步函数的结果,比如登录时,我们必须要在后台返回匹配成功的信息之后才能进行页面跳转,因此,使异步操作同步化这是很重要的知识点,但是这种方案是基于Promise的基础之上的,因此在学习该知识时,一定要对Promise有充分的理解

参考链接

https://juejin.cn/post/6844903984889593863

1
2
3
4
5
6
7
8
i = session.query(Model)
session.expunge(i)

old_id = i.id
i.id = None
session.add(i)
session.flush()
print(i.id) #New ID

修改从 SQLAlchemy 查询出来的模型会提交的缓冲里, 例如上述代码会导致查询出来的模型id被修改为None

如何分离一份模型出来使其修改不影响数据库的提交?

可以使用make_transient()函数

1
from sqlalchemy.orm import make_transient
1
2
3
4
5
6
7
8
inst = session.query(Model).first()
session.expunge(inst)

make_transient(inst)
inst.id = None
session.add(inst)
session.flush()
print(inst.id) #New ID

参考链接

https://docs.sqlalchemy.org/en/14/orm/session_api.html?highlight=make_transient#sqlalchemy.orm.make_transient
https://qa.1r1g.com/sf/ask/1024533471/

当使用 Javascript 调用函数的时候只能通过 return 返回一个值

1
2
3
4
5
6
const getAge = () => {
return 37
}
const getName = () => {
returnFlavio
}

当需要返回多个值的时候可以通过解构的方式获得

通过数组

1
2
3
const getDetails = () => {
return [37, 'Flavio']
}

通过数组结构, 我们可以这样获得

1
const [age, name] = getDetails()

现在我们有了agename包含这些值的变量

但是需要注意获取的顺序.

通过对象

也可以返回一个对象然后解构

1
2
3
4
5
6
7
const getDetails = () => {
return {
age: 37,
name: 'Flavio'
}
}
const { age, name } = getDetails()
1
const { age, name } = getDetails()

此时顺序将不再重要, 因为这些都是命名参数

参考链接

https://tech-wiki.online/tw/javascript-return-multiple-values.html