好久没有写过这种给自己"入门"的文章了. 不过最近看一篇文章强推Typescript, 还把js比作汇编, ts比作高级语言, 说你看现在还有几个人用汇编, 以后大家一样都是用ts的, 强推味道太重, 不过下载cocos creator, 也已经把ts作为默认语言了, 另外小程序也支持ts(似乎需要特殊设置一下,默认还是js), 再加上最近几年ts在语言排行榜上爬升很快, 看来不得不了解了.
参考教程:https://www.runoob.com/typescript/ts-features.html
在线playground: https://www.typescriptlang.org/play

安装

npm i -g typescript 即可, 安装后tsc可以运行就说明安装成功.

编译

tsc file.ts即可编译成file.js
在项目中, 可以先初始化文件夹tsc --init, 然后修改tsconfig.json,将"outDir": "./build",, 这样只运行tsc可以自动编译到build目录中.

REPL

由于运行tsc是用来编译的, REPL需要安装npm i -g ts-node, 然后运行ts-node即可.

类型定义: 变量后 : 类型名

如果:any则和js一样不限制类型.

  • 函数形参: 必须定义类型
  • let/const 变量: 可以不定义, 自动取初始化类型. 如果不初始化, 则类型为any
  • 对象成员: 可以不定义, 自动取初始化类型. 因为这个过于灵活, 所以有了interface关键词, 专门用来定义class的类型.

新关键字 interface implements

定义class需要遵从的形式

interface Person {
  name: string;
  age: number;
  greet(): void;
}

class Student implements Person {
  constructor(public name: string, public age: number) {}

  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

新关键字 type

定义新类型

type StringOrNumber = string | number;
let value: StringOrNumber = 42;

新关键词 as

因为js的不同类型有不同的方法, 有时候ts无法判断any类型,也就不知道这个变量有没有对应方法, 这时候就要用as来强制转换类型,以便访问该类型的方法

let value: any = "hello";
let strLength: number = (value as string).length;

新关键字 public private protected

定义对象成员的访问权限

新关键字 enum

定义枚举类型. 注意enum的定义方式比较像C语言, 没有赋值等号.

enum Direction {
  Up,
  Down,
  Left,
  Right,
}
let dir: Direction = Direction.Up;

很有意思的是Direction定义后, 在js中看起来是这样的

var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Down"] = 1] = "Down";
    Direction[Direction["Left"] = 2] = "Left";
    Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));

console.log

{
  '0': 'Up',
  '1': 'Down',
  '2': 'Left',
  '3': 'Right',
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3
}

貌似在新的浏览器和node(v20)中, enum都已经作为保留关键字了, 但还不能使用.

新关键词 abstract

与class的区别就是不能被实例化.

新类型 any

表示任何类型

新类型 unknown

与 any 类似,但更严格。必须经过类型检查后才能赋值给其他类型变量。

let value: unknown = "Hello";
if (typeof value === "string") {
  let message: string = value;
}

新类型 元组 tuples

这不是一个关键字, 而是允许定义具有固定数量和类型的数组

let point: [number, number] = [10, 20];

新类型 泛型 Generics

用尖括号<T>定义, 相当于T是可变化的类型(可以认为类型成了变量了), 在使用函数的时候再去定义类型.

function identity<T>(value: T): T {
  return value;
}

let num = identity<number>(42);

新类型 voidnever

void类型用于表示函数没有返回值,但可以返回undefined或null,并且函数可以正常执行并完成操作。
never类型用于表示函数永远不会返回任何值,通常是因为函数会抛出异常或进入无限循环。

function error(): never { throw new Error("error"); }

联合类型

用或|表示类型可以是几种之一

let id: string | number;
id = "123";
id = 456;

字面量类型

字面量类型可以让变量只能拥有特定的值,用于结合联合类型定义变量的特定状态。

let direction: "up" | "down" | "left" | "right";
direction = "up";

新运算符???

TypeScript 增加了 JavaScript 的可选链 (?.) 和空值合并运算符 (??),简化了代码中对可能为 null 或 undefined 值的处理。


let user = { name: "Alice", address: { city: "Wonderland" } };
console.log(user?.address?.city); // 如果 address 存在则输出 city,否则返回 undefined

let value = null;
console.log(value ?? "default"); // 如果 value 为 null 或 undefined,则返回 "default"
``
`?`确实简化了很多操作, 否则深度访问一个不存在的key, js就会报错.
`??`和`||`还是有区别的, `??`只判断null和undefined, 而`||`还会判断false, 0, 空字符串'', NaN.

  1. 美洲: 除了北美的美加两国说英语, 巴西说葡萄牙语外, 其他各个国家几乎都说西班牙语.
  2. 东南亚: 几乎各个国家都说各自的语言. 少数国家如新加坡, 菲律宾还使用英语. 当然新加坡通行4种语言,还包括华语,马来语和3. 泰米尔语. 另外老挝,缅甸,泰国本族语言是汉藏语系的衍生, 跟我国壮族,侗族,傣族等语言比较接近.
  3. 中亚: 中亚五国虽然都有自已的语言, 但由于苏联时代的影响, 俄语比较通用.
  4. 中东: 阿拉伯语比较通用. 少数不同是以色列说希伯来语, 伊朗说波斯语, 阿富汗说普什图语和达里语.
  5. 澳洲: 主要通行英语.
  6. 非洲: 几大殖民势力的语言都有通用.
  • 英语: 尼日利亚、加纳、利比里亚、塞拉利昂、冈比亚、肯尼亚、坦桑尼亚、马拉维、纳米比亚、博茨瓦纳、南非、斯威士兰、津巴布韦、赞比亚等国家将英语作为官方语言,
  • 法语: 包括刚果(金)、刚果(布)、科特迪瓦、卢旺达、中非共和国、多哥、几内亚、马里、布基纳法索、喀麦隆、乍得、科摩罗、吉布提、塞内加尔、马达加斯加、毛里塔尼亚、阿尔及利亚、摩洛哥、塞舌尔等
  • 葡萄牙语: 葡萄牙语是安哥拉、莫桑比克、圣多美和普林西比等国家的官方语言
  • 阿拉伯语: 在北非和部分东非国家广泛使用,是埃及、苏丹、利比亚、突尼斯、阿尔及利亚、摩洛哥、索马里、毛里塔尼亚、吉布提、科摩罗和乍得的官方语言

根据metaso AI的总结, 主要小语种在中国开设专业的大学数量:
俄语:174至181所大学
西班牙语:超过100所大学(具体数字在不同证据中有所不同)
阿拉伯语:41至10所大学(数据不一致)
法语:148至71所大学(数据不一致)
葡萄牙语:39至6所大学(数据不一致)

如果要与海外做生意, EF有一个英语熟练度指标,每年都会发布,而且还分别做中文和英文版本. https://www.ef.com.cn/epi/
2023年英文版: https://www.ef.com/assetscdn/WIBIwq6RdJvcD9bc8RMd/cefcom-epi-site/reports/2023/ef-epi-2023-english.pdf
2024年中文版: https://www.ef.com/assetscdn/WIBIwq6RdJvcD9bc8RMd/cefcom-epi-site/reports/2024/ef-epi-2024-simplified-chinese.pdf
可以看出, 除了英语母语国家, 拉美虽然说西班牙语, 但英语水平也是不赖的. 欧洲也是如此. 甚至在西班牙和葡萄牙都有不错的成绩. 但是在中东, 中亚, 南亚, 以及非洲的非英语国家, 英语熟练度就比较差了. 很奇怪的是英语国家印度的德里竟然评价为极不熟练.
EF的这个指标主要是通过在线自愿测试得出, 且年龄中位数为25岁.

想做像素动画,例如64x20px, 该怎么做?
尝试了几种思路

用视频编辑软件,可以自定义分辨率为64x20

PPT + Gif编辑

  • ScreenToGif (简称S2G)可以录制gif, 导出gif也能导出视频.
    这样用Powerpoint做动画,S2G录制. PPT上尺寸大一些, 录制的动图可以在缩小为需要的大小.

游戏的PNG Spritesheet技术

游戏一般把精灵角色的多个动作合并到一张PNG中, 这样加载起来更快. 这个想法最适合我.

打算用微信小程序将数据存为UTF-8格式的CSV,让Excel编辑.
使用wx.writeFile或者writeFileSync可以设置编码为UTF-8保存. 但此后的坑就连续不断出现了.
通过shareFileMessage转给自己, 用Excel打开, 就会发现是乱码. 原因是Excel只支持带BOM的UTF-8. 开始解决这个问题, 然而微信和Excel都有坑, 分别说下:

微信的系统差异

要给文件前面加UTF-8 BOM, 最简单是在保存的字符串前加入 \ufeff 再用writeFile+UTF8格式保存. 你会发现Android版本微信很好地完成了这个任务, Excel顺利打开, 然而ios版本微信会把你加入的\ufeff自动删除! 保存了个寂寞

微信用binary方式保存

问遍教程,都会让你用Buffer和TextEncoder通过UTF8编码转为ArrayBuffer前面再加入BOM头0xEF、0xBB、0xBF, 但是微信小程序不支持这两个常见的类Buffer和TextEncoder. 除非你自己实现一个.

微信曲线救国方式

碰到ios, 先保存,再读取,再在前面加入BOM头,再保存. 利用微信writeFile保存功能支持UTF8来解决

    tableStr = '\ufeff' + tableStr // 增加UTF8 BOM头
    const fs = wx.getFileSystemManager()
    fs.writeFileSync(filename, tableStr, 'utf-8')
    const deviceInfo = wx.getDeviceInfo()
    if(deviceInfo.platform == 'ios'){
      // 由于iOS系统上会把utf8保存的文件的前面的bom头删除(android不会),所以需要以arrayBuffer的方式读入文件之后重新加上utf8 BOM头。
      // 之所以不在内存中完成转换,而是通过文件读写的方式转换, 原因是内存中转换字符串到Utf8的两种手段Buffer/TextEncoder在微信小程序中都不支持。
      let file = fs.readFileSync(filename) 
      const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
      // 将文件内容转换为 Uint8Array 并合并
      const contentArray = new Uint8Array(file);
      const mergedArray = new Uint8Array(bom.length + contentArray.length);
      mergedArray.set(bom, 0);
      mergedArray.set(contentArray, bom.length);
      fs.writeFileSync(filename, mergedArray.buffer, 'binary')
    }

Excel的坑: 从2016版本才开始支持CSV UTF-8格式

如果你是2016以前的版本就不要挣扎了, 还不如用Win10/11上的记事本编辑了.

人也浪漫,字也浪漫,玉树银花自凋零。
来也如风,去也如风,犹记桃花笑盈盈。
弱水三千饮一瓢,我自逍遥。
莫为我死悲寂寥,翩然舞蹈。
-- 2024/12/4 纪念琼瑶去世

我感觉是不能着急,陷入要么全部让AI完成,要么完全不信任AI代码的极端。
程序员做的工作应该转向需求分析、概要设计、详细设计这些工作,将框架内的编码和单元测试留给AI来做。

C

一开始的简单任务, 都可以作对, 但是一旦开始出错, 如编译错误, 往往比较难改对.
最好一开始就用git, 修改正确后就立刻commit, 否则成果容易毁于一句话.
composer开新的会话要小心, 似乎新会话像一个新程序员, 跟旧的会话风格大不一样, 还可能大幅修改已经完善正确的代码
cursor写一个函数或一个文件中的几个函数是相对安全的, 整个项目大幅修改文件, 往往陷入编译错误数个回合不能自拔

在以下情况出过错, 加入.cursorrules看能否防止他再次出错

  • 在 Makefile 中,条件语句不能放在规则内部。
  • 请尤其注意函数先后的声明顺序,以及函数调用的顺序。
  • for循环的条件判断如果是变量x>0,并且x在每个循环中递减时, x的类型不能为unsigned, 否则不能退出循环.

B站上看到这么个视频https://www.bilibili.com/video/BV1H14y1p72L/
了解到还有这么一种玩法.大概意思是在电脑上通过docker开android虚拟机, 然后手机远程连接, 就像换了个手机一样.
基于视频的说法, 步骤是:

电脑端 手机端
容器 docker
虚拟机 redroid
私网 Zerotier
远程屏幕控制 ScrCpy

如果都在内网似乎Zerotier就不需要了.
另外虚拟机还可以开在云电脑或服务器上, 应该也不需要Zerotier.
感觉还有简单的方式, 就是在虚拟机中安装向日葵来远程控制. 只不过向日葵安装在虚拟机, 有可能会受限于虚拟机权限, 而ScrCpy安装在宿主机, 理论上不受虚拟机权限限制.

市监局 https://amr.sz.gov.cn/
房屋编码查询 https://tybm.szzlb.gov.cn:10000/AddressWeb/#/
经营范围查询 https://www.jyfwyun.com/home

如果注册选择秒批, 在选择经营范围的时候, 只有150个可选, 而实际上经营范围有1000~2000个.而且这一步比较靠后, 可能填了很多内容才出现经营范围选不了. 这时候只能删掉重选了.

秒批和正常注册流程有什么不同?

正常注册相对于秒批:

  1. 除了选择公司, 还能选择医疗或者其他要前置审批或特殊审批的企业.
  2. 公司名称里的行业用语可选项更多.
  3. 企业组织形式不限于内资有限公司.
  4. 股东不限于自然人
  5. 经营范围完整. 秒批只有完整范围的5%.

我的iqoo neo5又给摔了。 OLed屏幕不出意料的开始传染。因为第1次屏幕是我自己换的,结果到了vivo的门店里不保修了。工作人员说必须要原装屏幕才能享受折扣价450块钱换屏幕,否则这里850块钱还不如买新机了。
我看了一下二手机还没有换屏幕贵才六百多。
没办法,只好自己再买一个第三方的。上次买第3方的屏幕花了300多,当时就想不如换官方的屏幕。但是看到官方屏幕的价格是在我换屏幕之后。上次的第3方的屏幕有几个问题,一个就是显示区域小,第2个就是不支持指纹。
这次在淘宝上重新买了新的屏幕,价格260,据说支持指纹。这个屏幕带框架拆下来挺麻烦的,把所有的元器件全部拆光了,换到新的屏幕框架上。装完发现这个屏幕比第1次买的第3方屏还要小。第1次买的屏幕至少前摄像头是一个圆孔,这次直接变成了水滴屏。
测试完倒是确实支持指纹的。多点心理安慰。
在等屏幕的期间,我找备用机发现几乎所有的我用过的手机都被我屏幕摔碎了。看来屏幕在我手里摔碎是必然的。只是以前的屏幕都是lcd屏,摔碎了之后不会导致传染。
我找了一下现在比较强的lcd屏,发现iqoo z8是LCD最强的手机了,支持联发科8200,性能超出骁龙888。最大12gb+512gb。价格在1000~1200之间。
我看iqoo Z系列现在还在出新的lcd屏的手机,最新的z9用的是骁龙6系列的cpu,性能还不如z8。

主要政策

  1. 财政部 税务总局 发展改革委 工业和信息化部关于印发新疆困难地区重点鼓励发展产业企业所得税优惠目录的通知(财税【2021】42号) https://xinjiang.chinatax.gov.cn/zwgk/tzgg/202112/t20211221_93745.htm
  2. 财政部 税务总局关于新疆困难地区及喀什、霍尔果斯两个特殊经济开发区新办企业所得税优惠政策的通知
    财税〔2021〕27号 https://xinjiang.chinatax.gov.cn/sszc/zxwj/202107/t20210705_85628.htm
  3. 新疆困难地区重点鼓励发展产业企业所得税优惠目录 https://szs.mof.gov.cn/zhengcefabu/201910/t20191031_3413822.htm
    困难地区是指南疆三地州。南疆三地州是指喀什、和田、克州: http://cn.chinagate.cn/povertyrelief/2016-04/26/content_38327129.htm。霍尔果斯在伊利地区。
    总的来说,喀什可享受双重政策优惠。

    主要产业

    喀什本地农业特产是伽师新梅(西梅),近几年连年扩产。
    制造业在2023年增长大约30%。是增长非常快的产业。

进出口贸易

中亚五国:哈吉塔乌土,五个斯坦国。即:哈萨克斯坦、吉尔吉斯斯坦、塔吉克斯坦、乌兹别克斯坦、土库曼斯坦。其中哈吉塔从北到南依次与新疆接壤。其中哈萨克斯坦的面积最大,超过了其他4个国家的之和。哈国面积约为新疆+西藏。吉塔各自和广东差不多,乌土各自相当于四川面积。人口方面,哈国相当于深圳,约两千万人口,吉为600万,塔为1000万。乌3300万,土1000万。

喀什在全疆进出口贸易额排名第二。伊犁地区第一。主要面向中亚五国、共建一带一路国家。面向RCEP国家增长较快,但基数不明。
根据http://xian.customs.gov.cn/urumqi_customs/556645/556648/5679082/index.html 数据,2023年伊犁为931.1亿元,同比增长59.4%。其中机电产品增长65%,劳动密集型增长45%,说明其中机电产品正占据主流。其中90%以上为出口。99%为民营企业,57%出口到哈萨克斯坦。
喀什为836.8亿元,比伊犁少100亿,但同比增长71.2%,高于伊犁。其中主要产值来与喀什综合保税区,为496.5亿元,占比约60%。主要进出口方式为陆运,占喀什外贸进出口总值的88.5%。另外,喀什自贸区刚刚在2023年双十一落地(全疆自贸区包括乌鲁木齐、霍尔果斯、喀什)。其中机电产品增长103.8%,劳密产品增长55.7%。
乌鲁木齐以700.1亿元,同比增长36.5%,在全疆位列第三。从贸易伙伴看,哈萨克斯坦、吉尔吉斯斯坦、俄罗斯、乌兹别克斯坦、印度尼西亚为乌鲁木齐排名前五的贸易伙伴。中国新疆乌鲁木齐对上述国家进出口值分别同比增长48.5%、17.2%、59.7%、52%、8.3%。很神奇印尼这么远居然还有印尼。
以上可以看出:喀什是进出口贸易增长最快地区。乌鲁木齐应该是传统的进出口贸易地区,但增长已经相对比较落后。
喀什地区前四大贸易伙伴依次为吉尔吉斯斯坦、塔吉克斯坦、哈萨克斯坦、巴基斯坦。前两个是接壤国家。
http://paper.ce.cn/pad/content/202409/01/content_300396.html
喀什最重要的有个喀交会,其中还有专门与广东对接的分会场叫疆品南下、粤品北上。粤品北上主要是通过喀什进入中亚。

从喀什的国际贸易发展情况来看,跨境物流和跨境电商都处于快速增长时期。

其实,HTTP并不能直接访问云数据库,而是要通过云函数中介。也就是说,HTTP访问云函数,云函数访问云数据库。
在微信开发者工具中有个“云开发”按钮,里面可以管理云数据库和云函数。在如果小程序打开了云开发的支持,目录数中就会增加云函数的id目录,可以在这儿直接创建云函数。但事实上,创建云函数不止这一种方法,管理云数据库也不止这种方法,而要让http访问云函数,这里并不能开启http的访问权限。
事实上,云开发是属于腾讯云的一个服务,所以可以登录腾讯云的后台https://console.cloud.tencent.com/,找到云开发CloudBase这个服务。在环境管理中就可以看到微信小程序的对应的云开发环境。点击进去以后,选择访问管理-> Http访问服务就可以进行管理。
另外点击基础服务里的云数据库,页面将引导用户进入到一个专门的云开发平台的管理后台界面https://tcb.cloud.tencent.com/, 这里的功能微信开发者工具里面的云开发有点类似,但是设置的选项又要多一些。
腾讯云开发有专门的文档,跟微信者开发文档的域名不一样https://docs.cloudbase.net/,在这里也可以选择http访问服务的文档进行浏览学习。
这边的文档就提示进行云函数的创建和编辑,是有专门的命令行cli工具的https://docs.cloudbase.net/cli-v1/intro。这样可以通过命令行进行云函数的创建, 和微信开发者工具中创建的效果是一样的。并且命令行工具的功能要更多样一些, 比如说为http访问服务创建路由, 就只有用命令行工具才能做到。

示例项目配置

  1. 需要选择target为esp32c2
  2. 需要menuconfig配置flash容量和XTAL晶振。如果串口只能通过74880连接,说明晶振是26Mhz的,如果可以通过115200连接,则晶振是40MHz的。Flash如果配置不对,模组上电后会打印警告。晶振配置不对,蓝牙会找不到。我在淘宝买的这个https://item.taobao.com/item.htm?_u=ed01qc68e7&id=733669672310晶振就是26MHz、4M Flash,详情页说了4M Flash但是没有说26Mhz晶振。而Menuconfig默认配置是40Mhz+2MFlash。
  3. 下载乐鑫提供的配网APP。这个APP默认不会请求权限,需要自己去设置里面打开定位、蓝牙、附近设备等各项权限。
  4. APP打开后就能看到BLUFI DEVICE设备。

小程序实现

参考如下项目:
https://gitee.com/weijian.kang/esp-blufi-for-wx
该项目与上面的示例项目可以配网。不过仍存在一些问题,实际使用时候需要解决:
1、设备列表没有过滤,所有的蓝牙设备都会被扫描出来而不仅仅是blufi设备
2、错误的ssid和密码会导致界面卡在wx.showLoading界面。当然也可能是固件没有返回错误。
3、异步代码采用回调方式,回调地狱现象比较严重。最多的一行代码前面有42个空格(21个tab)
4、中文ssid发送的不对,在串口putty上显示的是乱码,而乐鑫官方发送的ssid在putty上显示正常
5、ssid需要手动输入
这个项目参考的另一个项目是
https://github.com/xuhongv/BlufiEsp32WeChat
这个项目readme虽然说只支持esp32,但esp32c2实测也是支持的。
似乎前面一个项目存在的问题都存在,只是功能似乎更强一些包括:
1、增加了本地ssid扫描和选择,根据界面提示是模组扫描的结果,但扫出来的wifi数量明显不足。
2、可在配网同时发送自定义的数据。但在putty打印上没有显示。当然这也可能是固件没有处理的原因。