Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS 对象神侃软硬链接与文件拷贝的区别 #62

Open
closertb opened this issue Sep 30, 2020 · 0 comments
Open

JS 对象神侃软硬链接与文件拷贝的区别 #62

closertb opened this issue Sep 30, 2020 · 0 comments

Comments

@closertb
Copy link
Owner

closertb commented Sep 30, 2020

前言

在Linux或MacOS系统中,ln命令是一个重要的命令,它的功能是为某一个文件在另外一个位置建立一个同步的链接。

对于前端来说,ln 命令被应用最多的地方就是, 就是全局安装并创建一个 npm 命令

npm i -g xxx(nrm)

当敲下回车,上面的安装执行完成后,在输出中,会看到这样一串字符:

/usr/local/bin/nrm -> /usr/local/lib/node_modules/nrm/cli.js

这串字符背后的意思就是系统建立了node_modules/nrm/cli.js 的软链接/bin/nrm

其实bin文件夹中的可执行命令,基本都是以软链接的形式存在。

更多关于 ln 的使用,可参考菜鸟教程

下面会围绕路径A 和 B 这两个实例来讲软硬链接和文件拷贝的区别:

路径A: /user/wam/A/request.js

路径B: /user/wam/B/request.js

request.js 内容

import utils from './utils';

console.log('res:', utils.res());

目录与文件

在开始前,简单回顾一下大学没学过,可能在那里看到过的文件系统,这里围绕简单易理解的Linux为例。
20200930152537
大部分的Linux文件系统(如ext2、ext3)规定,一个文件由目录、节点(inode)和数据块(block)组成

  • 目录项:包括文件名和inode节点号。
  • inode:又称文件索引节点,包含文件的基础信息以及数据块的位置。
  • block:包含文件的具体内容。

当我们随便打开我们某个开发项目,命令行输入ls -li, 就可看到目录与inode的对应信息,下图第一行就是目录对应的inode。
20200930150545

由于一个文件块(block)的大小有限(通常为4kb),所有常常一个文件需要存储在多个文件块中,这样 inode 就需要存储多个block的位置信息(如最上图所示), 而一个inode本身只有128 Btyes 的存储空间,所以存储文件block位置也是间接通过block来做的, 所以block 可以理解为分两种: 文件内容block 与 inode信息block,搞懂这些就可以往下了。

参考资料

软链接

软链接(soft link) 又被称为符号链接,相当于Window 系统中的快捷方式。

eg: 建立A 为 B 的软链接

ln -s /user/wam/B/request.js /user/wam/A/request.js

20201001081203
建立软链接 其实质就是某为路径的建立一个超链接(在这表现为 A 为 B的超链接),其不具有文件实体。当我们尝试打开A 路径所在的文件,其最终在编辑器打开的是路径B的文件,所以其文件内的相对路径引用文件也是相对路径B来计算的,即utils 文件路径为:

/user/wam/B/utils.js

当删除B文件,再去访问A, 会发现索引不存在,无法访问。

硬链接

硬链接(hard link), 是为源文件建立另一个索引。

eg: 建立A 为 B 的硬链接

// 少一个 -s 选项
ln /user/wam/B/request.js /user/wam/A/request.js

20201001081130
建立硬链接 其实质就是为文件实体创建另一个可访问的路径索引。所以当我们尝试打开A 路径所在的文件,与软链接区别的是:其最终在编辑器打开的是路径A自己,所以其文件内的 相对路径引用文件 也是相对路径A来计算的, 即utils 文件路径为:

/user/wam/A/utils.js

但值得一提的是,由于 A 与 B 路径都指向同一个源文件,所以在A路径对文件内容所做的编辑都会反映在 B 路径文件,即两边文件的变动是相互同步影响的。

当删除路径B时,源文件不会被垃圾回收,因为路径A 仍保持对源文件的索引。

硬链接和软链接还有一个区别是:因为系统的限制,硬链接要求路径是在文件维度,而软链接既可以是文件,也可以是文件夹。

文件拷贝

这个应该用过电脑的人都懂。

eg: 拷贝文件B 到路径 A

// 少一个 -s 选项
cp -f /user/wam/B/request.js /user/wam/A/request.js

20201001081041
文件拷贝,是日常我们最常见的操作,只是更常见的形式是用ctrl + c/v,而非cp 命令(实际上cp 也能实现ln链接的操作), 其实质就是拷贝一份文件实体并创建一个可访问的路径索引。所以当我们尝试打开A 路径所在的文件,其指向的实体是不同于B的(克隆体),所以其文件内的相对路径引用文件也是相对路径A来计算的即utils 文件路径为,与建立硬链接一致:

/user/wam/A/utils.js

由于 A 路径 与 B 路径 都分别指向自己的实体,所以A/B各自是独立的,当删除B时,B对应的源文件会被回收,A不受任何影响。

神侃JS对象与硬软链接

作为前端我们都知道,JS对象(object)是引用类型。

引用类型的值是保存在内存中的对象。JS 不允许直接访问内存中的位置,即不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的。(摘抄自红宝书 P87)

你品,你细品。是不是感觉 引用类型 和我们上面讲到文件链接与源文件很像 !

以:

const B = { a: 1 };

20200911111937

所以当执行下面这种操作:

const C = B;

C.a = 2;

console.log('B.a:', B.a); // 2

B.a = 3 
console.log('C.a:', C.a); // 3

从上面的执行输出,我们可以很容易看出,原来JS中的引用类型变量赋值和硬链接 是一回事。

接着我们引入一个lodash 的深拷贝(cloneDeep)函数:

import { cloneDeep } from 'lodash'

const C = cloneDeep(B);

C.a = 2;

console.log('B.a:', B.a); // B.a: 1

B.a = 3 
console.log('C.a:', C.a); // C.a: 2

从上面的执行输出,我们可以很容易看出,原来JS中的深拷贝和文件拷贝 是一回事。

软链接怎么用 JS 来描述呢?Proxy?

Proxy 中文译作代理,在表现上其实是与硬链接一致的,而硬链接与软链接从表现上最大的区别就是:B(母体) 被删除后,A(超链接)就不可访问了,所以这并不是正确的答案。

而正确答案是:WeakRef,弱引用. 当下处于proposal阶段,不过在Chrome 与 Firefox 最新的版本都对其做了实现;

看个demo:

let B = { a: 1 };

const C = new WeakRef(B);

const registry = new FinalizationRegistry(heldValue => {
  console.log('GC worked:', heldValue); // GC worked: B
  // 当B所指向的值被垃圾回收后,这个回调将被执行
  console.log('C.a:', C.deref()?.a); //C.a: undefined
});

// 注册B所指向的值被垃圾回收的监听
registry.register(B, "B");

console.log('C.a:', C.deref().a); // C.a: 1

C.deref().a = 2; // 通过索引改变值

console.log('B.a:', B.a); // B.a: 2

B.a = 3;

console.log('C.a:', C.deref().a); // C.a: 3

// 切断对值得索引, 观察上面的GC 回调
B = null;

// console.log('after C.a:', C.deref()?.a);

貌似上面的JS代码能勉强阐述软链接的原理,但离理想确实还有距离,这个神侃更多的是想让大家对ES新提案中的WeakRefFinalizationRegistry有一个感性的认识。

更多关于 WeakRef 请阅读

结语

通过本文,你是不是发现,这世间万事万物是不是特别奇妙。虽然是神侃,读到这里,希望你能有一丝丝收获。

@closertb closertb changed the title 神侃JS 对象与软硬链接与文件拷贝的区别 JS 对象神侃软硬链接与文件拷贝的区别 Oct 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant