分类 未分类 下的文章
Cursor试用: 震撼!
Cursor试用非常震撼。我第一次用就想尝试一下一直以来想做的一个东西: 就是通过Chrome浏览器来用蓝牙BLE连接设备。之前在b站上看过Chrome浏览器支持蓝牙的视频, 这对我来说是一个完全不熟悉的新的API。然后就尝试用cursor, 看他的能力如何。竟然从无到有。一两个小时的时间完全编写了一个蓝牙BLE的调试器。从HTML到css到JavaScript。从书写逻辑到页面布局。
看看Cursor的成果吧! BLE Scanner
浏览器去调试BLE设备有一个缺陷, 就是要搜寻的服务必须预先定义。
使用node的http-server开启本地https服务
官方文档
首先需要用openssl创建证书. windows环境下如果找不到openssl, 可以进入bash
创建后再exit
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
创建中问好几个name,其中问到common name
的时候,要填写127.0.0.1
, 其他时候用默认值就可以. 完成后在本目录下会生成证书文件
启动https服务:
http-server -S -C cert.pem
小拇指和半个无名指麻木,前臂内侧酸胀疼痛:尺神经综合症(肘管综合症)
鼠标手一般被叫做腕管综合症。这主要是因为鼠标用的是食指和中指,这两个手指的神经是由腕管中的神经来控制。而我的症状则不一样,是小拇指和无名指。我感觉是因为小拇指的负担太重,打键盘太多导致的。小拇指要负责非常多的按键,再加上enter键这个用很多的按键。
因此我想未来鼠标和键盘可能会被淘汰。即使是在生产力工具中,例如笔记本电脑和台式机。因为鼠标和键盘会带来的身体的健康问题,对手指神经的危害,未来势必会被其他的输入方式所取代。一种方式就是语音输入。但是语音输入的准确度不高,并且无法进行中英文混合的准确输入。这对日常办公打中文倒是没有太大问题,然而对于编码的话就问题比较大,还有就是干扰周围的人,并且对噪音非常敏感。还有一种方式就是通过思维。马斯克正在做的脑机接口如果能应用于普通人,则是一个伟大的进步。现在的脑机接口必须嵌入式植入一个芯片在大脑皮层上面。嗯未来如果要普通人使用,则不能用这种侵入式的方式。
尺神经受压通常指的是尺神经综合征(Ulnar Nerve Compression Syndrome),又称肘管综合征(Cubital Tunnel Syndrome)。它是由尺神经在肘部或前臂受压迫造成的,常见症状和相关治疗方法如下:
症状
-
麻木与刺痛:
- 小拇指及无名指的麻木或刺痛感,尤其是在手肘屈曲时更为明显。
-
疼痛:
- 肘部内侧或前臂内侧可能感到疼痛,通常伴随刺痛感。
-
握力减弱:
- 在抓握物体时,可能会发现握力减弱,影响抓握能力。
-
运动障碍:
- 有时可能出现手指协调能力下降,例如难以完成细致的动作(如扣扣子)。
-
肌肉萎缩:
- 长期受压可导致小拇指根部或无名指根部肌肉萎缩,使得该区域看上去凹陷。
治疗方法
-
非手术治疗
- 休息:避免重复性的手部和肘部活动。
- 物理治疗:使用拉伸和加强练习,以恢复正常功能。物理治疗师可以帮助设计个性化的锻炼方案。
- 护具:佩戴护具(如肘托)以保持肘部在良好的位置,特别是在夜间。
- 药物治疗:使用非处方的消炎药,如布洛芬等,可以缓解疼痛和炎症。
-
手术治疗
- 如果非手术治疗效果不佳且症状持续加重,医生可能建议进行手术。常见的手术方式包括:
- 尺神经减压术:通过释放对尺神经的压迫。
- 尺神经转位术:将尺神经移动到一个更少受压迫的位置。
- 如果非手术治疗效果不佳且症状持续加重,医生可能建议进行手术。常见的手术方式包括:
注意事项
如果您有上述症状,请尽快就医,以便进行专业评估并制定相应的治疗计划。尽早干预有助于改善预后。
虽然尺神经受压和腱鞘炎(Tenosynovitis)都是与手部和腕部相关的疾病,但它们是不同的状况。
尺神经受压
- 定义:尺神经受压通常指的是尺神经在肘部或前臂位置受到压迫,导致其通行受阻,并引发一系列症状,如麻木、刺痛和疼痛。
- 症状主要包括:小拇指和无名指的麻木感、掌握力减弱以及肘部内侧疼痛等。
腱鞘炎
- 定义:腱鞘炎是指肌腱周围的腱鞘发生炎症,导致滑动不畅和疼痛。常见于重复性运动或过度使用导致的肌腱疲劳。
- 症状主要包括:局部疼痛(通常是在手腕或手指部位)、肿胀、触摸时有压痛感,以及活动受限。
主要区别
- 病因:尺神经受压通常是由于解剖结构问题(如肘部位的压迫),而腱鞘炎通常与过度使用或外伤有关。
- 出现位置:尺神经受压症状集中在小拇指和无名指,而腱鞘炎则多集中在关节处,如手腕、拇指根部等。
总结
总之,这两种病症虽有相似之处,但应根据具体的症状及体检结果进行区分。如有疑问或出现相关症状,请咨询医生以获得准确诊断和治疗建议。
微信小程序固定元素位置的两种形式
一种是页面json不变, 使用css属性position: fixed;
,同时规定css属性 top bottom left right
.
第二种是可以在页面的json文件中写: "disableScroll": true
, 然后再元素上使用css属性position: absolute;
,再规定css属性top bottom left right
. 这种方式是结合recycle-view
来用的, 原因太久不太记得了, 似乎因为Recycle-view的一些特性导致position:fixed不能正常固定或页面不能正常滚动.
微信小程序的页面如何知道是从哪儿进入的?
进入一个页面有几种方式: navigateTo,navigateBack, 熄屏再显示(从其他应用切换回来也是类似).
GPT给的建议是通过app.globalData存储全局变量来判断, 或者用storage存储判断, 感觉都不优雅, 把单个页面问题的解决扩展到了全局去了. 但目前还没有其他好办法, 因为navigateBack和熄屏再显示都是触发onHide,所以无法区分.
GPT还给了一个幻觉建议, 说onShow会带形参进来,判断形参就可以, 但事实上onShow不会带任何形参
通过navigateTo,navigateBack从其他页面导航到这个页面, 通常都需要更新页面数据. 因为上一页导航过来, 这一页的数据还没有生成过; 从下一页返回, 可能在下一页对数据做了更新.
CSS flex-box
因为CSS的flex每次用的时候总是忘记, 这儿总结一下:
将flex理解为一个画框(父元素)里面的元素(子元素)的排列.
父元素设置整体遵从的规则, 子元素设置个别规则.
总体规格包括:
- flex-direction: 确定主轴方向. 元素是沿着主轴方向依次放置的. 交叉轴(副轴)即主轴的垂直轴, 确定一行主轴放不下的元素,下一行放的方向.
- flex-wrap: 元素在主轴放不下, 要不要回车放在下一行.
- justify-content: 确定元素主轴排列, 以及元素间距
- align-items: 确定副轴的元素排列
- align-content: 确定wrap后多行的元素怎么放置,以及行间距等.
京东E卡的小滑头
银行送了10元京东E卡,进了京东APP完全找不到绑定的地方, 搜索兰搜索京东E卡也只是给了一堆的卖E卡的连接. 说是付款的时候京东自营商品可用, 然后下了好几个单,专门找京东自营,充话费,京东超市和京喜自营买纸巾,付款的时候都没有选择E卡的界面. 找了一圈只好问机器客服, 这才找到绑卡的地方: 我的钱包-点击查看全部-礼品卡
,此时注意不要点那个大大的京东E卡
图标, 而要点击绑定新卡
! 然后输入卡的密码, 只用输入密码, 而不用输入卡号, 虽然给了卡号但并没有什么用.
然后, 我去找下单但没有付款的链接, 还是不能选择! 接着下新单, 也没有选E卡的地方! 我勒个去, 赶快百度找下经验, 发现百度经验这个下单支付界面怎么和我不一样? 终于发现了, 原来从购物车购买,点击去结算
才有这个选礼品卡(京东卡/E卡)订单界面, 这个订单界面选择地址, 查看订单详情,选择开票等等.
从商品链接直接购买真的不能选择吗? 我又研究了下,发现不是的!商品链接里面直接点击下单购买(这个名字在不同的商品链接还不一样, 有的叫到手价购买
, 有的叫立即购买预估
), 这时候不会转到新页面,而是从下方弹出来一个半屏, 上面显示收货地址,选择商品数量和规格, 平常这个时候就选"支付"了, 但注意, 这个半屏是可以上滑的! 你如果上滑一点点, 发现滑出来的只是其他商品的广告, 但如果继续上滑, 才出现商品价格详情,支付方式,发票,留言...等等这些订单信息, 全部堆在这个半屏的最下面, 跟从购物车结算的订单界面是类似的. 但是等等, 为什么礼品卡的选择消失了? 哈哈,这时候还要去选择商品金额栏目里的四个灰色小字:展开更多
,才看得到优惠券
和礼品卡
两个选项,不得不说比购物车结算订单界面要隐蔽得多.
京东这个界面设计真的很滑头, 其逻辑是想方设法让你别用券直接支付, 让你确认地址/品类/数量这些最重要信息后就直接付款, 这样 一方面京东拿到最多的钱, 另一方面你买了以后即使想到有优惠券, 也只能下次用了, 又引诱你下次继续在京东购物. 之前几次买东西找不到开票的地方也是这个原因.
微信小程序的组件
引用自定义组件
组件名 | 组件json-> | 页面json-> | 页面wxml |
---|---|---|---|
mycomp.js/.json/.wxml/.css | {"component": true,usingComponents": {}} |
{"usingComponents": {"mycomp": "../../components/mycomp/mycomp"}} |
<mycomp></mycomp> |
组件展现页面的数据和自身的数据
没有区分. 如
`Component({
properties: {propFromPage: 1},
data: {propFromData: 2}
})
在组件wxml中都是同样方式引用{{propFromPage}} {{propFromData}}
. 但在组件js中引用方式有区分:this.properties.propFromPage, this.data.propFromData
调用函数
组件中的函数引用方式在js中不需要加methods
, 如
`Component({
properties:{prop:{type: Number, value:1, observer(newValue, oldValue){this.f1();}}},
lifetimes:{attached(){this.f1();}},
methods: {
f1(){},
f2(){this.f1()},
}
})
页面向组件传数据
页面js-> | 页面wxml-> | 页面wxml | 组件js |
---|---|---|---|
Page({data:{pageprop: 1}}) |
<mycomp prop="{{pageprop}}"></mycomp> |
{{prop}} |
Component({ properties: {prop: 默认值}, methods:{f(){this.properties.prop },}}) |
组件向页面传数据(通过事件)
组件js-> | 页面wxml-> | 页面js |
---|---|---|
Component({method:{f(){this.triggerEvent('someevent', somevalue) },}}) |
<mycomp bind:someevent="processIt"></mycomp> |
processIt(e){let value = e.detail} |
数据库设计:绘制实体关系图(Entry Relationship Diagram, ER图/E-R图/ERD)
有两种不同文档描述了两种不同的ER图, 一种是把属性放在实体外面https://zhuanlan.zhihu.com/p/270299029, 另一种是把属性和实体放在一起https://blog.csdn.net/character_/article/details/124142908.
后者看起来更美观些.
draw.io可以画ER图.
js如何在对象的键值变化时调用函数, 并且操作对象的代码不需要变动(无感)
GPT4o给了三种方法, 在后面给出. 第三种方法是改赋值=
为调用函数, 意味着所有的赋值都要改为函数调用,不实用. 分析下方法一Proxy和方法二getter/setter.
Proxy的好处是不会改变原对象,而是建立了一个新的proxy对象, 对新对象的赋值会触发set函数. 问题有三个: 一是任何键值变化都会触发set,需要自己判断键值; 二是需要将原对象的名称指向新proxy对象, 才能实现无感. 三是无法通过instanceof
判断pr一个实例是不是Proxy的实例, 只能自己在创建实例时添加一个自定义key如_isProxy
来判断.(后面段落说明)
getter/setter是最早一代vue.js用的方法, 所有在app.data中的键都会用Object.defineProperty()
的get/set重定义一遍, 做到自动更新UI. 好处是可以逐个key定义,不影响其他key, 问题是原key值就会消失,除非定义前先保存一下. 并且需要保存到另一个键下面(一般前面加个下划线_
)而不能保存在本key下面, 否则会导致反复触发直到调用栈溢出Maximum call stack size exceeded
.
这个话题在vue的官方文档中也有讨论: https://cn.vuejs.org/guide/extras/reactivity-in-depth, 里面也提到在vue3中,从getter/setter已经转向了proxy机制.
另外一个问题, 是如果键值是一个对象(数组也是),也就是下面有子键, 对子键键值的修改, 只会调用get而不是set!并且对Proxy和getter/setter机制都一样. 如:
proxyObject.k = {k1:1} // 调用set
proxyObject.k.k1 = 2 //调用get
怎么解决这个问题,GPT4o的回答是递归代理. 见后面一节.
方法1: 使用Proxy
在 JavaScript 中,如果希望在对象的某个键变化时自动调用一个函数,可以使用 Proxy
对象来实现。Proxy
允许你创建一个代理对象,以便对其属性的访问和修改进行拦截。
下面是一个使用 Proxy
的示例代码,当对象的 someKey
属性变化时,会自动调用函数 a
:
// 定义要监控的对象
const targetObject = {
someKey: '初始值',
};
// 定义要自动调用的函数
function a(newValue) {
console.log(`someKey 的新值是: ${newValue}`);
}
// 创建 Proxy 代理对象
const proxyObject = new Proxy(targetObject, {
set(target, property, value) {
// 当设置 someKey 时,调用函数 a
if (property === 'someKey') {
a(value);
}
// 修改属性的值
target[property] = value;
// 返回 true 表示设置成功
return true;
}
});
// 测试:修改 someKey
proxyObject.someKey = '新的值'; // 这将输出: someKey 的新值是: 新的值
// 可以继续修改其他属性也不会触发 a()
proxyObject.anotherKey = '另一个值';
console.log(proxyObject.anotherKey); // 输出: 另一个值
说明:
- 在上面的示例中,创建了一个对象
targetObject
和一个函数a
。 - 使用
Proxy
创建了代理对象proxyObject
,并在其set
拦截器中定义了逻辑。当someKey
被修改时,会自动调用函数a(newValue)
。 - 修改其他属性不会触发这个函数,只会在指定的键发生变化时执行。
通过这种方式,你可以灵活地监控对象属性的变化,并根据需要触发相应的逻辑。
方法2 使用getter/setter
你可以使用 JavaScript 的 Object.defineProperty()
方法来定义 getter 和 setter,使得每次修改对象属性时都能执行相应的函数。
const targetObject = {
_someKey: '初始值', // 私有变量
};
// 定义要自动调用的函数
function a(newValue) {
console.log(`someKey 的新值是: ${newValue}`);
}
// 使用 Object.defineProperty 定义 getter 和 setter
Object.defineProperty(targetObject, 'someKey', {
get() {
return this._someKey;
},
set(value) {
this._someKey = value;
a(value); // 调用函数 a
},
});
// 测试:修改 someKey
targetObject.someKey = '新的值'; // 这将输出: someKey 的新值是: 新的值
// 读取 someKey
console.log(targetObject.someKey); // 输出: 新的值
// 可以继续修改其他属性也不会触发 a()
targetObject.anotherKey = '另一个值';
console.log(targetObject.anotherKey); // 输出: undefined (因为没有定义)
方法3:使用自定义方法
另一种简单的方法是创建一个用于更新对象属性的方法,以便所有更改都通过此方法发生,这样就可以在里面调用相关逻辑。
const targetObject = {
someKey: '初始值',
};
// 定义要自动调用的函数
function a(newValue) {
console.log(`someKey 的新值是: ${newValue}`);
}
// 自定义方法用于更新键并执行相应逻辑
function setSomeKey(value) {
targetObject.someKey = value; // 更新属性
a(value); // 调用函数 a
}
// 测试:修改 someKey
setSomeKey('新的值'); // 这将输出: someKey 的新值是: 新的值
// 读取 someKey
console.log(targetObject.someKey); // 输出: 新的值
// 修改其他属性的方法不变,不会触发函数 a()
targetObject.anotherKey = '另一个值';
console.log(targetObject.anotherKey); // 输出: 另一个值
如何知道实例是Proxy的实例
在 JavaScript 中,可以使用 Proxy
对象来创建代理,从而控制对某个对象的基本操作,如属性查找、赋值、枚举、函数调用等。如果想要判断一个对象是否是一个 Proxy 实例,可以通过以下方法:
-
利用 WeakMap: 在将对象包装为 Proxy 时,可以使用
WeakMap
来存储原始对象和其代理之间的关系。通过这种方式,你可以检查某个代理是否存在于这个WeakMap
中。const originalObject = {}; const proxyMap = new WeakMap(); const proxy = new Proxy(originalObject, { set(target, prop, value) { return Reflect.set(target, prop, value); } }); // 存入 WeakMap proxyMap.set(proxy, originalObject); function isProxy(obj) { return proxyMap.has(obj); } console.log(isProxy(proxy)); // true console.log(isProxy(originalObject)); // false
-
标记法: 你可以在创建 Proxy 时在其内部设置一个标记属性,以便后续判断。
const originalObject = {}; const proxy = new Proxy(originalObject, { get(target, prop) { if (prop === '_isProxy') return true; return Reflect.get(target, prop); } }); function isProxy(obj) { return obj && obj._isProxy === true; } console.log(isProxy(proxy)); // true console.log(isProxy(originalObject)); // false
-
使用
instanceof
关键字: 不幸的是,直接通过instanceof
来判断是否为 Proxy 是不可能的,因为我们无法直接访问 Proxy 的构造函数。
总的来说,上述方法是较常见的判断一个对象是否为 Proxy 的方案。选择适合自己需求的方法来实现即可。
递归代理
要解决object下的key是对象或者数组, 其子键或者子元素被修改时调用的是get而不是set的问题, GPTo答复是递归代理. 下面给出的是对象的递归代理, 实际还需要考虑数组.
递归代理是对了,但是GPT4o在第一次给出的代码中并没有实现递归代理,指出后,在第二次实现了递归代理, 但设置深层子元素的时候调用了2次set(重复代理了),指出问题后, GPT4o再修改了6次, 也没能回答正确. 感觉是黔驴技穷啦. 这儿贴出其中一次的代码.
function createReactiveObject(obj) {
return new Proxy(obj, {
set(target, property, value) {
// 检查设置的值是否为对象
if (typeof value === 'object' && value !== null) {
// 用 Proxy 处理该对象
value = createReactiveObject(value);
}
// 设置实际值
target[property] = value;
console.log(`属性 ${property} 被设置为: ${value}`); // 输出变更信息
return true; // 返回成功标识
},
get(target, property) {
const value = target[property];
// 仅当获取的是对象时才返回新的代理,避免递归代理产生重复
if (typeof value === 'object' && value !== null) {
return createReactiveObject(value); // 利用递归返回新的代理而不是多次创建同一对象的代理
}
return value;
}
});
}
// 创建动态对象并使用代理函数包裹它
const dynamicObject = createReactiveObject({
k1: { k2: { k3: {} } } // 初始化嵌套结构
});
// 测试:设置嵌套属性
dynamicObject.k1.k2.k3.k4 = 20; // 应只输出一次: 属性 k4 被设置为: 20
// 打印查看当前状态
console.log(dynamicObject);
做了个event发送和超时等待程序, 结果小程序不能用, 只适用于node
node版本
作为tools.js
的功能, 代码如下
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();
// 事件发射
emitEvent(event, arg){
eventEmitter.emit(event, arg)
},
//等待事件, 成功则返回args, 失败则返回null
async waitEvent(event, timeout = 500){
return new Promise((resolve, reject) => {
let timer = setTimeout(() => {
reject(timeout) // 如果用await waitEvent(),则抛出异常值为timeout
}, timeout)
// 监听消息事件
const messageListener = (arg) => {
clearTimeout(timer); // 清除定时器
eventEmitter.removeListener(event, messageListener); // 移除监听器
resolve(arg); // 解决Promise,返回数据
};
eventEmitter.on(event, messageListener); // 添加监听器
})
}
使用示例:
f = async ()=>{
setTimeout(()=>tools.emitEvent('laugh',"hahaha"), 100)
try{
let res = await tools.waitEvent('laugh', 500)
console.log("res is", res)
}catch(e){console.log('timeout', e)}
}
f() // 打印: res is hahaha
英语ob开头却有不同的发音和不同的意思
obligation(义务) obviously(显然地),其中的ob-
读作/ɒb/, 词根是强调的作用, 重音在o
. 而oblivious(健忘的)的obliv-
读作/əˈblɪv/,词根是遗忘的意思, 重音在b
.
JSDoc注释js代码的规范
参考https://juejin.cn/post/6995464881205936164
/**
* @description 描述fn的作用或功能
* @param {string} a 参数描述
* @param {number} [b] 参数描述
* @param {boolean} [c=false] 参数描述
* @param {array} arr 参数描述
* @param {string} arr[0] 参数描述
* @param {number} [arr[1]=undefined] 参数描述
* @return {number} 描述返回值
*/
阿里云这个网址有99元/年的ECS
https://www.aliyun.com/benefit
99元首年,第二年1000左右. 如果只是建站还是很适合,大不了到期迁移一下也不费多少功夫