谈谈软件行业普遍存在的`立即数`和`引用数`

事情是这样的, 最近没事玩玩前端的polyfill, 就是填充浏览器的标准库, 之前写了几篇, 比如<Fuck标准库系列:Object.prototype.filter>, <赶在标准化前构造一个RegExp.escape方法>, 然后昨天公司里做Vue前端路由的时候需要实现一个url参数的封装, 就封装了一个window.location.parameter.

 

Fuck标准库系列: location.parameter

整个url中从左到右分别是: 协议, 主机名, 域名, 端口号, 路径, 查询参数, 于是window.location对象有:

  • location.href
  • location.protocol
  • location.host
  • location.port
  • location.pathname

但是唯独缺少了最后面的查询参数, 于是我们封装一下吧, 通过location.href后面分割"?", "&", 以及"="字符来把键值对封装成一个js对象, 于是我写了一句话代码:


location.param = (decodeURIComponent(location.href).split('?')[1] || '')
  .split('&')
  .map(p => p.split('='))
  .reduce(
    (p, [key, value]) => (key ? Object.assign(p, { [key]: value }) : p),
    {},
  );

测试一下, 打开 https://www.baidu.com/s?ie=UTF-8&wd=JavaScript , 输入以上代码, 然后打印location.parameter:

location.parameter;

> {ie: "UTF-8", wd: "JavaScript"}

嗯, 效果不错, 没啥技术含量, 只是用到MapReduce有点绕, 仔细看看就能明白.

反正才写了一点点, 就扯点别的吧, 打发下时间.


`立即数`和引用的普世思想

上面提到的url参数是在url中寄存了一些轻量的数据, 而不是将数据放在请求返回的结果中, 这2种数据存放方式有一个很经典的区别: 前者是"立即数", 后者是引用. 立即数是直接存放在地址中的数据, 而引用是需要通过地址, 经过一次查找后才能得到的数据.

这看上去很明显啊? 为啥非要写出来呢? 因为这种现象在软件行业非常常见, 上升到一个普遍适用的哲学地位. 下面举几个例子:

 

有请求的url和无请求的url

以一个图片url为例, 通常都是通过一个图片地址比如https://example.com/test.png来获取图片, 但如果图片很小, 就可以直接将图片的数据信息放在url中, 比如复制下面这个url会在浏览器中打开一张svg图片, 但没有发送任何请求:

data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve" height="100px" width="100px">
<g>
    <path d="M28.1,36.6c4.6,1.9,12.2,1.6,20.9,1.1c8.9-0.4,19-0.9,28.9,0.9c6.3,1.2,11.9,3.1,16.8,6c-1.5-12.2-7.9-23.7-18.6-31.3   c-4.9-0.2-9.9,0.3-14.8,1.4C47.8,17.9,36.2,25.6,28.1,36.6z"/>
    <path d="M70.3,9.8C57.5,3.4,42.8,3.6,30.5,9.5c-3,6-8.4,19.6-5.3,24.9c8.6-11.7,20.9-19.8,35.2-23.1C63.7,10.5,67,10,70.3,9.8z"/>
    <path d="M16.5,51.3c0.6-1.7,1.2-3.4,2-5.1c-3.8-3.4-7.5-7-11-10.8c-2.1,6.1-2.8,12.5-2.3,18.7C9.6,51.1,13.4,50.2,16.5,51.3z"/>
    <path d="M9,31.6c3.5,3.9,7.2,7.6,11.1,11.1c0.8-1.6,1.7-3.1,2.6-4.6c0.1-0.2,0.3-0.4,0.4-0.6c-2.9-3.3-3.1-9.2-0.6-17.6   c0.8-2.7,1.8-5.3,2.7-7.4c-5.2,3.4-9.8,8-13.3,13.7C10.8,27.9,9.8,29.7,9,31.6z"/>
    <path d="M15.4,54.7c-2.6-1-6.1,0.7-9.7,3.4c1.2,6.6,3.9,13,8,18.5C13,69.3,13.5,61.8,15.4,54.7z"/>
    <path d="M39.8,57.6C54.3,66.7,70,73,86.5,76.4c0.6-0.8,1.1-1.6,1.7-2.5c4.8-7.7,7-16.3,6.8-24.8c-13.8-9.3-31.3-8.4-45.8-7.7   c-9.5,0.5-17.8,0.9-23.2-1.7c-0.1,0.1-0.2,0.3-0.3,0.4c-1,1.7-2,3.4-2.9,5.1C28.2,49.7,33.8,53.9,39.8,57.6z"/>
    <path d="M26.2,88.2c3.3,2,6.7,3.6,10.2,4.7c-3.5-6.2-6.3-12.6-8.8-18.5c-3.1-7.2-5.8-13.5-9-17.2c-1.9,8-2,16.4-0.3,24.7   C20.6,84.2,23.2,86.3,26.2,88.2z"/>
    <path d="M30.9,73c2.9,6.8,6.1,14.4,10.5,21.2c15.6,3,32-2.3,42.6-14.6C67.7,76,52.2,69.6,37.9,60.7C32,57,26.5,53,21.3,48.6   c-0.6,1.5-1.2,3-1.7,4.6C24.1,57.1,27.3,64.5,30.9,73z"/>
</g>
</svg>

截图:

同理, 各种mime类型都可以通过data:协议来实现无请求的url, 或者"立即得到"的媒体

 

粘贴板

电脑的粘贴板一般只能存放一种类型的数据,比如一段文本,一张图片,但如果你尝试复制一个文件或者很大的一张图片,粘贴板中的内容将不再是文件本身而变成一份引用,文件移除后引用将失效,对吧?

 

软链接文件和硬链接文件

我们知道文件系统都有文件名与数据,这在 Linux 上被分成两个部分:用户数据 (user data) 与元数据 (metadata)。用户数据即文件数据块 (data block),是记录文件真实内容的地方;而元数据则是文件的附加属性,如文件大小、创建时间、所有者等信息。在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)才是文件的唯一标识而非文件名。文件名仅是为了方便人们的记忆和使用,系统或程序通过 inode 号寻找正确的文件数据块。下图展示了程序通过文件名获取文件内容的过程。

可以类比面向对象语言中变量与对象之间的关系: 变量是对对象的引用, 用户只能通过变量来和暗箱中的对象打交道. 这里元数据就是变量, 数据块就是对象. 我们日常接触的每一个文件都分成这2个部分, 元数据和数据块一一对应才有意义, 那有没有这样一个很小的文件, 它只有元数据(文件头), 没有文件块呢? 还真有, 这就是硬链接文件.

为解决文件的共享使用,Linux 系统引入了两种链接:硬链接 (hard link) 与软链接(又称符号链接,即 soft link 或 symbolic link)。链接为 Linux 系统解决了文件的共享使用,还带来了隐藏文件路径、增加权限安全及节省存储等好处。若一个 inode 号对应多个文件名,则称这些文件为硬链接。换言之,硬链接就是同一个文件使用了多个别名.

软链接与硬链接不同,若文件用户数据块中存放的内容是另一文件的路径名的指向,则该文件就是软连接。软链接就是一个普通文件,只是数据块内容有点特殊。软链接有着自己的 inode 号以及用户数据块。因此软链接的创建与使用没有类似硬链接的诸多限制.

举个通俗的例子, 你创建一个txt文档, 打开在里面写上: "file:Users/test/hello.png", 保存关闭, 然后重新命名为hello.png.softlink, 再写一个简单的程序向OS注册.softlink的文件打开方式, 读取其中的文本内容后调用系统的默认打开方式打开目标路径的文件, 这样一个软链接系统就完成了.

下图说明了软链接和硬链接的区别:

 

变量和对象

这个不再陌生了, 基础数据类型和引用数据类型的最大区别就是前者将数据直接存放在栈空间中, 特点是查找速度快, 后者通过栈空间的引用定位到堆空间的数据, 特点是数据容量大. 这种模式和文件系统很像: 使用栈空间来节省成本, 提高查询速度; 使用堆空间来提高系统灵活度, 为数据共享提供可能.

我们的认知过程大致是先意识到栈空间的存储能力, 再意识到可以把较大的数据存放到堆中; 但真实的发展模式是, 将所有数据存在堆中, 通过变量栈暴露给用户一个索引, 之后优化的时候再将一些比较轻巧的数据比如数字, 字符和boolean直接存到变量中.

 

CPU的立即寻址和直接寻址

CPU的设计也遵守着堆栈的思想.

cpu的寻址方式就是处理器根据指令中给出的地址信息来寻找有效地址的方式,现在情况很鲜明了, CPU每次得到的这几个字节即有可能是相关数据的地址(即直接寻址), 也有可能是数据地址的地址(即间接寻址), 还有可能就是数据本身(即立即寻址). 如果非要和文件系统的操作做一个对照的话:

  • 立即寻址 ---> 删除一个硬链接文件
  • 直接寻址 ---> 读取一个普通文件
  • 间接寻址 ---> 读取一个软链接文件

完.


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xosg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值