分类 未分类 下的文章

参考1 https://www.digitalocean.com/community/tutorials/host-a-web-server-on-android
参考2 https://wiki.termux.com/wiki/Remote_Access

概述过程:参考1的作者先是把termux整改了一番,比如启用sshd,把默认命令行从bash改成了fish等等,然后才开始正式行动。

pkg update && pkg upgrade
pkg install apache2 git neovim wget curl
# 下面装的这些只是优化
pkg install openssh neofetch fish nmap
# 设置一下ssh的登录密码
passwd
# 启动sshd,记住端口是8022
sshd
# 看一下自己的用户名和ip
whoami
ifconfig

然后可以从pc上登录:ssh -p 8022 username@ipaddr

下一步可选,是把命令行改为fish的

chsh /data/data/com.termux/files/usr/bin/fish
fish

如果8080被占用,修改一下apache配置,端口号改为8000,nano ../usr/etc/apache2/httpd.conf
运行服务

apachectl 

使用webdav server 连接

参考 https://blog.csdn.net/SilentCWQH/article/details/127559615

pkg i apache2
cd $PREFIX/etc/apache2
nano httpd.conf

httpd.conf把下面行前面的#去掉并保存:

LoadModule dav_module libexec/apache2/mod_dav.so
LoadModule dav_fs_module libexec/apache2/mod_dav_fs.so
LoadModule dav_lock_module libexec/apache2/mod_dav_lock.so
LoadModule auth_digest_module libexec/apache2/mod_auth_digest.so
Include etc/apache2/extra/httpd-dav.conf

看一下Listen哪个端口,默认应该是8080,可以按自己需要修改,特别是端口被占用的情况:

Listen 8080

nano httpd-dav.conf修改其中内容,设置别名和真实路径,我设置的是downloads路径,也可以设置storage/shared路径,可以访问手机全盘:

Alias /downloads "/data/data/com.termux/files/home/storage/downloads"
<Directory "/data/data/com.termux/files/home/storage/downloads">

创建webdav的账号密码,似乎必须是admin,以和上面httpd-dav.conf中的内容对应起来

htdigest -c "/data/data/com.termux/files/usr/user.passwd" DAV-upload admin

创建密码。这儿如果忘记了也没有关系,重新运行一次这个命令再创建新密码就行了。

启动服务:

httpd -k start

如果要重启服务,可以先用pkill httpd杀掉服务再启动。
如果有什么异常。查看log,在$PREFIX/var/log/apache2/

客户端

参考:https://www.jianshu.com/p/7ba5f0756efc

MAC上用finder>前往>连接服务器添加如:http://192.168.2.2:8080/downloads这样的形式即可连接访问。用户名admin,密码就是上面创建的那个。

其他推荐的软件还有RailDrive, bitkinex. windows上使用可在本站搜索 webdav参考群晖搞机的文章。

启用samba server,并通过windows连接

termux 安装samba

pkg install samba
cp $PREFIX/share/doc/samba/smb.conf.example $PREFIX/etc/samba/smb.conf
cd $PREFIX/samba
cp smb.conf smb.conf.backup
nano smb.conf

主要是启用guest登录,并设置共享路径。修改:

map to guest = Bad User
guest ok = yes
path = @TERMUX_HOME@/storage/shared

path应该不需要改,默认是共享sdcard全盘的。
启动smb服务:smbd。如果报错,有可能是有的软件不配套,更新一下:

pkg update
pkg upgrade
smbd

注意,由于android限制端口, smbd默认启动端口是4445,而windows默认是445端口。termux在很多手机上是不能提权为root的。
这儿有一个问答:https://superuser.com/questions/702948/how-to-mount-a-samba-share-on-non-standard-port似乎能解决,因为要下载运行一个脚本,暂未测试。
第一个答案:

This is possible! It's been a good few years, but combining a loopback interface tutorial I found with portions out of @Mike's [..link-only] answer (multihost version) I've created a script that can do this for you.

You can use this after running Install-Module -Name LoopbackAdapter -MinimumVersion 1.2.0.0 in an admin terminal (dont forget to dot-source the script so you can call this).

Create-Host -Name bob -Ip 10.254.0.1 -Dest ipOfHostname -Port port
which [upon reboot] will allow you to go to \bob (fake IP 10.254.0.1) which attaches to your "hostname:port" from your question.
This will persist across boots and you don't need to re-run it if the source server goes up or down; teardown is as simple as Retire-Host -Name bob.

That easy, one command, programmatic, no gui/windows settings dialogs; but feel free to follow along below manually.

翻译过来就是:先在powerscript用admin运行Create-Host -Name bob -Ip 10.254.0.1 -Dest ipOfHostname -Port port,然后运行作者的ps1脚本https://gist.github.com/Hashbrown777/081e57ff9673a1f457e1c3a71b55cfaf#file-attachsmb-ps1-L61, 然后就可以使用\\bob连接目标设备了。

苹果和安卓的时间构造函数new Date()不同

在安卓手机上可以接受new Date('1971-1-1'),而在苹果手机上这样构造出来的是Date <Null>, 苹果只能接受new Date('1971-01-01')这种形式的构造, 也即是必须严格遵循yyyy-mm-dd, 前面要补零.

云开发打不开或者白屏

微信开发者工具有时候会悄无声息的升级, 有时候给你升级到RC版, 有时候升级到不带RC但是也不是stable的版本. 这两个版本都会遇到这种问题. 版本回退就好了. 如果是RC版,可能要退两次,也就是RC->普通版->Stable版

不同的日志功能与费用

小程序有小程序的日志, 云函数还有云函数的日志.

小程序的日志有两种: 本地日志和实时日志.

  • 本地日志用log = wx.getLogManager()获取日志管理器对象使用, 需要用户手动上传日志. 原话是用户可以通过使用 button 组件的 open-type="feedback" 来上传打印的日志。 logManager官方文档
  • 实时日志用wx.getRealtimeLogManager()获取管理对象, 微信自动管理上传策略. RealtimeLogManager官方文档. 实时日志需要登录小程序后台, 从“开发->开发管理->运维中心->实时日志”进入日志查询页面。目前已经并入We分析. 然后We分析有基础和专业版之分, 专业版要收费. 影响是: 基础版只支持5000条/天开发数据上报, 并且保存7天, 开发数据包含小程序日志、插件日志、性能事件.

云函数日志也分基础和高级. 高级也是要收费的. 可以在开发工具的云函数面板中查看.

进入页面的方法的不同(GPT生成)

小程序中,有几个不同的方法可以用来进行页面跳转,包括wx.navigateTo、wx.navigateToMiniProgram、wx.redirectTo和wx.reLaunch。这些方法之间存在以下区别:

wx.navigateTo:用于打开新的页面,并将其加入页面栈中。新页面打开后,可以通过返回按钮返回上一个页面。
wx.navigateToMiniProgram:用于打开其他小程序。当调用该方法时,会打开目标小程序,并且会在当前小程序后台运行,用户可通过左上角的关闭按钮返回到当前小程序。
wx.redirectTo:用于关闭当前页面,并打开新的页面。被关闭的页面将会被销毁,新页面会替换原来的页面。
wx.reLaunch:用于关闭所有页面,并打开新的页面。所有已存在的页面将会被销毁,仅保留新打开的页面。
需要注意的是,以上四个方法均需要在App.json文件中对应的页面路径进行配置。此外,redirectTo和reLaunch方法可以进行跳转传参,而navigateToMiniProgram方法可以进行跳转传参和附加数据传递。
另外, 小程序组件navigator具有所有这些打开页面的功能.

页面unload并不会吧页面的js也onload. 所以第一次进入页面和第1+N次进入页面的表现是不同的.

因为js文件本身只会加载而不会卸载, 因此:
页面onload以后, 随着页面一起load的页面js并不会unload, 在第1+N次进入页面的时候, 这个js并不会重新运行.

区别点 第一次进入页面 第1+N次进入页面
页面js 加载, 不在Page()函数中的所有代码在这一次执行 不加载(已经加载过了), 所有代码不会再执行了
执行顺序 执行js->data数据初始化并保存初始data数据->调用onload() 执行js->d微信会用第一次保存的原始data再次初始化data->调用onload()

所以, 如果在page的data外初始化了全局变量, 就要保证在onload中重新初始化, 否则仍然遗留上次界面的数据造成判断错误. 最佳实践是全局变量都在onload中做初始化.

但对于定义在app.json中的tabBar页面则不需要, 因为tabBar只会onload一次.所以写tabbar页面必须时刻知道无论是页面还是js都不会卸载.

阿里企业邮箱有个功能, 员工账户删除后, 会转移到账号回收站中保留30天, 在这儿可以点击删除的邮箱后面的转移邮件按钮, 将它转移到其他邮箱中, 比如一个集中的邮件存档邮箱, 并且是集中存储在一个文件夹中的
也可以用foxmail把邮件收下来以后再删除, 也可以和上面的方法结合,把存档邮箱收下来. 但注意要使用imap, 不要用pop3, 因为pop3收不了邮箱文件夹里的邮件.

参考How to Configure Proxy Settings on Ubuntu 20.04

命令行运行:

export HTTP_PROXY=[username]:[password]@[proxy-web-or-IP-address]:[port-number]
export HTTPS_PROXY=[username]:[password]@[proxy-web-or-IP-address]:[port-number]
export FTP_PROXY=[username]:[password]@ [proxy-web-or-IP-address]:[port-number]
export NO_PROXY=localhost,127.0.0.1,::1

export http_proxy=[username]:[password]@[proxy-web-or-IP-address]:[port-number]
export https_proxy=[username]:[password]@[proxy-web-or-IP-address]:[port-number]
export ftp_proxy=[username]:[password]@ [proxy-web-or-IP-address]:[port-number]
export no_proxy=localhost,127.0.0.1,::1

大小写都要设置, 因为有的程序认大写, 有些(curl)认小写.
如果需要长期生效, 可以把上面的内容加到~/.bashrc里面
但是这个对apt不起作用. apt要生效, 需要修改文件: /etc/apt/apt.conf,增加:

Acquire::http::Proxy "http://[username]:[password]@ [proxy-web-or-IP-address]:[port-number]";
Acquire::https::Proxy "http://[username]:[password]@ [proxy-web-or-IP-address]:[port-number]";

用df -h查看Ubuntu server, 应该是有150G硬盘, 但实际上只看到73G

Filesystem                         Size  Used Avail Use% Mounted on
tmpfs                              392M  1.1M  391M   1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv   73G  6.8G   62G  10% /
tmpfs                              2.0G     0  2.0G   0% /dev/shm
tmpfs                              5.0M     0  5.0M   0% /run/lock
/dev/sda2                          2.0G  129M  1.7G   8% /boot
tmpfs                              392M  4.0K  392M   1% /run/user/1000

了解到有个LVM的东西, 意思是Logical Volume Manager.
参考LVM与磁盘配额原理及配置实例, Linux中的LVM逻辑卷管理(你真可爱,我说时来不及思索,而思索之后,还是这样说)
LVM可以便于动态在磁盘上调整容量.
ubuntu--vg-ubuntu--lv 的意思是 vg: virtual group, lv: logical volume.

管理命令:

功能 物理卷管理 卷组管理 逻辑卷管理
scan扫描 pvscan vgscan lvscan
create建立 pvcreate vgcreate lvcreate
display显示 pvdisplay vgdisplay lvdisplay
remove删除 pvremove vgremove lvremove
extend扩展 ———— vgextend lvextend
reduce减少 ———— vgreduce lvreduce

除此之外的辅助命令:

lsblk
fdisk -l

谁能想到呢。既然想不到哈马斯突袭以色列,也不会想到以色列夷平哈马斯。
加沙里面是巴勒斯坦管,但围墙是以色列管,相当于以色列“关押”巴勒斯坦人的巨型监狱。跟其他监狱一样,暴动了就要镇压。狱警这次打算一劳永逸,干掉所有犯人。狱警早就想这么做了,这回正好有个借口。
不是真杀完。加沙两百万人,杀完得用原子弹了。赶到埃及去确实对于以色列是最理想的做法。现在以色列的策略是极限施压加沙,把加沙人都压到气球唯一的泄气阀、最南端的lafa crossing. 只要压力足够大,让巴勒斯坦人自己一拥而出,埃及也无法阻止,毕竟埃及不可能枪杀巴勒斯坦人,而以色列可以。只要事实上赶走绝大多数犯人,以色列对剩下的暴动分子一一清洗就不是多么难的事情。如果有普通人不走?那也当做暴动分子。
以色列认定埃及会打碎牙往肚里咽。一定会给埃及造成难民危机,但埃及这次不会给巴勒斯坦人武装。

差评原文: 都说电车换电是血亏 结果隔壁小电驴换电都赚麻了

时间线:

  • 2016年 出现一些换电企业. 此时主要给家用, 此时家用需求不高.
  • 2017年 外卖大爆发, 续航不足. 此时外卖小哥有三种方案: 1. 容量超大的电动车; 2. 买两台换着开; 3. 换电. 成本而言第二种显然高很多. 1和3各有优劣
  • 2019年 电动车数量暴增, 国家出台电动车国标, 限速/限重/限功率. 上述1类车生产受到限制. 换电企业宇谷科技成立.
  • 2020年 一年新增换电相关企业超过1400家
  • 2023年 宇谷科技营收和净利润3年年增长120%~150%, 龙头企业铁塔换电收入为宇谷科技3倍以上. 多数入局企业难以继续存活
  • 未来 预期市场还将持续增长

按上述时间线, 这个行业发展至今有六七年时间, 已经几乎要完成淘汰赛, 进入成熟期.
这个行业有很典型的发展过程. 市场从不认可到大爆发, 国家监管从无到有, 入局企业从暴增到如今的快速淘汰.
应该分析除了产品采用率曲线(和市场规模/用户数曲线比较接近)外, 企业数曲线. 企业应该区分上下游. 靠近市场的下游企业会提前发展, 暴增并提前淘汰. 如果国家监管进入, 按利好利空, 会加速企业暴增或淘汰. 上游企业发展有一定滞后性. 并且下游企业淘汰后还有一定缓冲期向存留优质企业供货.
这儿需要判断企业是否有能力进入. 绝大多数企业都需要在市场快速上升阶段发展盈利(明星产品), 并在成熟期成为稳定现金牛.
其实换电的门槛有点像共享充电宝, 需要产品前期投资布点, 并且重运营, 需要在各个城市布人维护. 从这一点就不适合所谓小而美的公司或者能力上只能做小而美的企业做. 再加上电动车行业事关交通安全和充电安全, 应预计到发展起来后国家必然监管, 监管必然带来加速行业竞争和洗牌, 此时也需要更大数量级的资金维持本企业扩张速度. 所以就对自有资金和外部融资能力提出了考验.
然后再判断进入的时间点. 最佳的时间点应该是在国家监管之前0.5~1年时间. 在此期间要能预计到行业的快速增长以及伴生的安全事故将在未来触发国家监管, 并能分析监管会为换电行业带来何种契机. 在这个时间点进入可以避免前期的混乱探索等待期(家庭换电还是哪种市场?), 有相对明确的上升市场(外卖员), 有一段时间的充足准备,可以正好遇到行业的爆发和监管对行业的促进和洗牌.

在专注做事的过程中, 干扰是一件非常讨厌的事情. 人为什么讨厌干扰? 为什么有干扰? 如何避免? 谈下想法.
如果把人比喻成电脑, 那么人就是一个时分复用的系统, 并且堆栈非常浅并且容易丢失, 切换任务非常耗时并且一定会引起堆栈丢失. 人在专注做一件事情的时候, 说明事情本身是要花费较长时间的, 人对此时此刻事情的理解, 情绪情感, 推论步骤, 创意灵感都存储在稍微大些的瞬时记忆和小的不能再小的短时记忆里, 并且还要进行和长时记忆里相关的内容产生互动. 此时一切换任务, 首先丢失的就是瞬时记忆, 切换任务稍微长几秒钟, 短时记忆也丢失了, 切换的任务时间更长, 人不得不将中断点记录在长时记忆中或者干脆写在纸上, 但中断点只能记录在哪儿中断, 却不能记录情绪情感, 大脑里临时形成的理解推论这些东西. 所以处理完干扰后, 从中断点继续做事时, 忘掉的东西是找不回来的. 如果忘掉的东西会影响继续做事, 那人不得不在中断点往前回溯一段来找回这一部分东西, 但找回来的只能相似而不能相同, 甚至也不够完整, 不够强烈, 并且浪费了时间.
干扰产生的原因是人与其他人之间的直接或间接的连接, 产生于其他人对自己的可能的请求. 讽刺的是, 这个请求仅仅只是"可能的"而不是必然的, 也就是相关性并不一定很大甚至不存在. 人与人之间的连接是必须的所以干扰就不可避免. 而现代科技社会为人与人创造了更多更方便更廉价的连接方式. 这就带来的多得多的干扰. 因为连接变得廉价甚至免费甚至自动化了, 干扰源就不太在乎请求与被干扰者的相关性. 然而相关的可能始终存在, 人也不得不去评估相关性, 评估相关性本身又变成了新的干扰.
干扰源来自于通讯设备和人. 通讯设备干扰包括实时语音和消息. 联系太方便导致人们有需求的时候会立刻联系别人; 微信拉群太方便, 群里面莫名其妙的消息发个不停; APP发通知太方便, 广告消息和似乎重要却并不重要的消息不停弹出. 这让人真的有些怀念固定电话和信件的时代, 只有在家的时候能收到电话, 而且陌生人也不知道自己的号码.信件往返以周计算, 那么迟几天回复也不是问题. 如果比较起来, 古代人大概更加幸福, 唯一的联系方式是信件, 家书抵万金, 想不专注都不行啊.
因为通讯方式只会原来越便利, 所以必须要学会避免干扰. 避免人的直接干扰就是呆在一个没有人或者只有陌生人的环境中, 比如咖啡厅或图书馆. 避免通讯的干扰, 只有关掉微信开飞行模式了. 电脑上我把微信隐藏到右下角, 眼不见心不烦. 这种大概就要面对其他人的愤怒, "为什么不接电话"或者"为什么不回微信"之类. 然而这种规则却是必须的, 如果无法专注, 则无法做事, 更无法提升自己.
对于靠连接生存的人来说就比较困难, 比如销售岗位就无法做到, 大概也注定了销售岗位的人比较难以专注于长时间做一件事情.

进入正题前先说为什么扣一星。
作为纪录片,为了说明自己的观点,选择论据的时候,有一定倾向性是很正常的。然而本片有些过于明显的矫揉造作,无病呻吟。有几个方面:一是在与反面论点的被采访者谈话时(尤其第二集),主持人故意抢话,故意想要显出对方要争辩却无力(喊不过主持人)的感觉;二是为了显得事实更惊悚,有打击面过于宽广的嫌疑,尤其是第二集和第三集把玩具、游戏、动画、广告产业挨个批一遍,似乎这些产业本不该存在一样,这些产业不会消失,合理的方式是去更严格规范,而不是只是骂一通过过嘴瘾。最后,特别讽刺的一点是,本片某种程度自己变成了自己所批判的那一类产品,也就是为了让观众消费自己(观看自己),而竭力去制造一些冲突去讨好观众,引起兴趣,甚至在客观证据的基础上额外制造没来由的恐惧和焦虑(对反面行业的恐惧和焦虑)以显示自己的价值。
除去这些本片还是非常值得一看的,那么下面进入正题。
首先,从本片的主要目标受众消费者——或者说是被消费主义反复蹂躏的消费者的角度入手讲起。
什么是消费主义?我认为,消费主义就是把购买等同于幸福,买的越多越幸福,因为消费让你全知全能,当然可以幸福。不可否认,购买解决了自己的需求或欲望,确实带来的满足感,问题在于,消费主义认为消费解决一切问题。消费当然不能解决一切问题,那么,消费主义为了解决那些他本不能解决的问题,唯一的做法就是欺骗。
一是关于“保质期”。计划报废事实上就是给没有保质期的产品也加上了保质期,让用户可以在保质期结束之后购买新的产品。所有产品都会在使用中损耗。损耗到什么程度,产品就用不了?这其实不好说,也就有了人为操作的空间。如果我可以垄断市场,就故意把产品设计的短命一些,就像片子开头的灯泡;我也可以设置一个损耗标准,比如规定使用多少次或损耗多少百分比就不能用了,就像打印机的墨盒和苹果的电池;甚至我可以简单的规定一个期限,比如汽车的保养周期,第一次买车的车主如果没按保养周期保养,恐怕心里都有种焦虑,怕车会坏掉或者出事故吧。说到保质期,我想再提一下食物,恐怕食物的保质期也不是像它所说的这样,过期马上就吃不了了吧,那到底过期后能不能吃?消费主义再一次成功引发了焦虑感。
二是关于不能解决的需求,抗衰老确实是一个挺好的例子,虽然不能像片子里面这样一棍子把所有抗衰老产品都打死,但确实有挺多欺骗老年人的产品。片子里展会上那种扫一扫就知道你身上有什么病的,还有咱们那些经常卖给老年人的各种稀奇古怪,包治百病的保健品。真的追究起来,大多数跟脑白金功效差不多。至于脑白金的功效,我估计跟可口可乐差不多。
三是创造不存在的需求,比如明明没有病,非要说你病了,然后卖给你药。
其次,从生产者角度讲起。因为生产者是逐利的,他们看本片完全可以从反方向来看:如何卖出更多的东西。
当然,现在越来越多的大公司开始重视绿色循环经济。比如片中的宜家受访者,就是宜家的可持续发展部门的负责人。主持人去诘问他多少有些无厘头,作为一个部门负责,大概并不能干预话语权更重的营销部门的决策,最多只能是影响。就像他自己说的,把这些影片给他们看。
其实,这些都是消费者驱动的。如果消费者更愿意购买绿色环保的产品,厂家当然也更愿意生产。而消费者的意愿是媒体和广告共同塑造的,前者靠媒体从业者,后者的约束只能靠国家政策,因为打广告的人永远都是顶着广告法允许的极限去打的。
最近,欧盟出台政策要求手机电池必须消费者自己可更换,这也是政策驱动生产者做出改变的例子。本片在对ifixit的采访中也提到了手机越来越薄越来越难以修理,不单单是生产者的“计划报废”,更是消费者本身对于轻薄的外观追求。如果要便于维修,对于外观的某些方面最求可能就要被牺牲掉,而外观却是消费者购买产品的最大考虑因素,可维修性对消费者来说可能忽略不计。一旦外观重要性增加,产品就趋向于时尚产品,换代速度就只会变得更快。
可维修性这个方面,面向企业的2B产品可能会做得更好。因为2B产品外观的重要性要低一些,而可维修性作为降低成本的一个环节,其重要性会更高一些。
其实,在这个节奏越来越快的商品社会之前,几乎所有东西都是可维修的。世界兜兜转转,也许会再次将可维修性作为商品的重要属性提出来并写入法律条文中。这样,生产者在设计产品时将不得不考虑可维修性。
最后,说说环保主义者如何看待本片。应该是感到震惊的浪费吧,尤其是产品的计划报废,让很多本来还能使用的东西过早地丢进了垃圾堆。片中只提到了耐用品,其实对于食品也是一样,B站上有一个在法国捡过期面包的视频,面包店的后厨成箱成箱丢掉的面包,完全可以再次食用。其实我觉得对于环保主义者来说,多消费些电影游戏更好吧,因为在消费这些产品的过程中几乎没有丢弃什么东西,对环境产生什么危害。

wiki上paper size词条比较全面, 我这儿仅列出常见的以及和屏幕尺寸的对比.

名称 mm长 mm宽 mm对角线 in对角线 接近的印刷品 接近的屏幕尺寸
A0 841 1189 1456.3 57.3 - -
A1 594 841 1029.6 40.5 - 40寸电视
A2 420 594 727.4 28.6 - -
A3 297 420 514.4 20.2 - -
A4 210 297 363.7 14.3 A4纸 14寸平板
A5 148 210 256.9 10.1 笔记本 10寸平板
A6 105 148 181.4 7.1 - 7寸手机
A7 74 105 128.4 5 - 5寸手机
B0 1028 1456 1782.3 70.1 - 70寸电视
B1 707 1000 1224.6 49.5 - 49寸电视
B2 514 728 891.1 35 - -
B3 364 514 629.8 24.7 - 24寸显示器
B4 257 364 445.5 17.5 - 17寸笔记本电脑
B5 182 257 314.9 12.4 - 12寸平板
B6 128 182 222.5 8.7 - 8寸手机
1K 780 1080 1332.2 52.4 - -
2K 540 780 948.6 37.3 - -
4K 390 540 666.1 26.2 - -
8K 270 390 474.3 18.6 - -
16K 195 270 333 13.1 小学课本 13寸平板
32K 135 195 237.1 9.3 练习本 9寸平板
64K 97 135 166.2 6.5 6寸手机

我发现生活中有的产品,其功能或者华而不实,或者使用频次很低,或者是用一个更大、更贵、更复杂的方案解决了一个简单问题,然而却卖得非常好。为什么卖得好?有时候是满足了虚荣,有时候是满足了想象的需求,有时候是从众心理。

  • 汽车天窗、天幕。用过天窗的都知道一年开不了几次天窗,甚至开不了几次天窗遮阳板。天幕更是如此,不能打开还晒得慌,车主不得不为此再买遮阳布并且大多数时间不会在把布取下来。这个产品显然增加了成本,但现在几乎要成为家用汽车标配了。在天窗刚刚开始一定是高端、高配、豪华车才有的,这种“我有钱我买了我不用”显然是满足了虚荣。有的站在“实用主义”的角度设想天窗平时可以“开窗透气、仰望星空、接触自然”,想象乘车人在乡间林荫小道探出脑袋享受清风,然而绝大多数时间却是在城市通勤使用,这满足了想象的、几乎不存在的需求。在大家都买有天窗的汽车后,不买总觉得不大对劲,这是羊群效应、从众心理。
  • 饮水机,尤其是立式的。饮水机也经历一个从豪华到标配、到泛滥的过程。90年代一开始谁家里喝桶装水,一定是高大上的象征,特别是比水桶还要大、还要高一倍的立式饮水机,大大的体积似乎在暗示里面有很复杂的装置。事实上,饮水机里面绝大部分空间是空的,热水加温并不需要多大体积,成本也不高,以至于饮水机后来变成了水店的赠品。二三十年前家庭电器少、房间大的时候放一个饮水机不是大问题,现在则显得非常占用空间。

如题.

// 9实际指的10月. 因为数值表示的月份取值区间是0~11
new Date(2023,9,12)
//输出 Thu Oct 12 2023 00:00:00 GMT+0800 (中国标准时间)
new Date('2023-10-12')
//输出 Thu Oct 12 2023 08:00:00 GMT+0800 (中国标准时间)

也就是以数值构建date, 结果为中国时间的当天0点, 以字符串构建date,结果为UTC时间的当天0点, 中间差了8小时. 所以在程序中构建date时要注意方式的一致性.

chatGPT3.5不能正确回答, GPT4可以. 如下:

在JavaScript中,new Date(year, month, day)和new Date(dateString)它们创建日期对象的方式是不同的:
new Date(year, month, day):这种方式创建的日期对象,年份、月份、日期都是基于本地时间。JavaScript 数组中月份是从0(一月)开始计数到 11(十二月),所以9其实代表的是10月。
new Date(dateString):如果只提供了一个表示日期的字符串参数,那么该字符串应该按以下格式之一:YYYY-MM-DDTHH:mm:ss.sssZ或者只有日期部分 YYYY-MM-DD, 并且解析为 UTC时间(格林尼治时间)。如果你直接使用new Date('2023-10-12'),那么它会被解析为在UTC时间2023-10-12T00:00:00.000Z,假如你所在的时区比UTC时间早8小时,那么实际上你获得的时间会是2023-10-11T16:00:00.000Z。
由于上述两者不同的工作方式,即使看起来他们似乎在构造相同的日期,但可能得到的Date对象实际上代表的确是两个不同的时间点,表现在getTime()返回的毫秒数上就可能会有差异。
你可以使用 toISOString() 方法来验证这个问题,比如 console.log(new Date(2023, 9, 12).toISOString()) 和 console.log(new Date('2023-10-12').toISOString()),你会看到他们确实是返回了不同的结果。

更加神奇的是, new Date("2023-1-1")和new Date("2023-01-01")都会差一个时区:

new Date('2023-1-1')
> Sun Jan 01 2023 00:00:00 GMT+0800 (中国标准时间)
new Date('2023-01-01')
> Sun Jan 01 2023 08:00:00 GMT+0800 (中国标准时间)

iOS上new Date("2023-1-1")是不能用的, 必须严格输入yyyy-mm-dd形式.

关于时区可以算是一个Bug, 这篇文章做了详细解释: Web Fundamentals: Avoid These JavaScript Date Object Pitfalls
它列举了这几种构造方式导致时区时有时无:

// ISO 8601 without time: defaults to midnight UTC time
const withHyphen = new Date('2023-01-01') // Sat Dec 31 2022 18:00:00 GMT-0600 (Central Standard Time)
withHyphens.getTime() // 1672531200000

// ISO 8601 set to UTC timezone (same as not providing time)
const noOffset = new Date('2023-01-01T00:00:00.000Z') // Sat Dec 31 2022 18:00:00 GMT-0600 (Central Standard Time)
noOffset.getTime() // 1672531200000

// ISO 8601 set to Local Timezone
const withLocalOffset = new Date('2023-01-01T06:00:00.000Z') // Sun Jan 01 2023 00:00:00 GMT-0600 (Central Standard Time)
withHyphens.getTime() // 1672552800000

// Well Recoginized String Format - Defaults to Local Timezone
const withSlashes = new Date('2023/01/01') // Sun Jan 01 2023 00:00:00 GMT-0600 (Central Standard Time)
withSlashes.getTime() // 1672552800000

// Number Arguments - Defaults to Local Timezone
const withArgs = new Date(2023, 0, 1) // Sun Jan 01 2023 00:00:00 GMT-0600 (Central Standard Time)
withArgs.getTime() // 1672552800000

说原因是 ECMAScript标准在解析ISO 8601日期字符串的时候有瑕疵(flawed), ISO 8601意思是要加上时区, 而ESMAScript没加时区, 发现问题想改的时候已经成为事实标准改不了了. 所以后面其他的实现方式都是按ISO 8601的, 包括/分隔符和使用数字构建, 或者使用yyyy-m-d方式构建. 最坑爹的是使用yyyy-m-d方式构建, 当日期从10月9日变到10月10日时, 就会突然失去时区.
另外文中还提到一个问题,就是 new Date(null)是可以构建出正常的Date的,时间戳为0, 也就是1970-1-1, 这就和正常认知有些违背. 不过 new Date(NaN)是不能构建的.