目录
新建一个标签(默认为HEAD,也可以指定一个commit id)
一、Git
Git 是一个分布式版本控制系统,用于跟踪和管理项目代码的变化。它是一种广泛用于协作开发和版本控制的工具,使开发人员能够有效地协同工作、跟踪代码更改、还原到以前的版本以及解决代码冲突。
以下是 Git 的一些重要概念和特性:
-
版本控制:Git 能够记录项目中每个文件的历史变化,包括修改、添加和删除。这意味着您可以随时查看文件的不同版本,并回滚到任何特定版本。
-
分布式系统:Git 是一种分布式版本控制系统,这意味着每个开发者都有一个完整的代码仓库副本。这使得开发者可以在离线状态下工作,然后将更改同步到其他开发者的仓库中。
-
分支(Branches):Git 允许您创建分支,这是基于主要代码的副本。分支可用于并行开发多个功能,而不干扰主要代码。一旦功能完成,可以将分支合并回主要代码。
-
提交(Commits):Git 的核心概念之一是提交,每个提交都是一组文件更改的快照,并附有描述。提交是项目历史的基本单位,它们形成一个有向图,表示代码的演变。
-
远程仓库(Remote Repository):Git 支持远程仓库,允许多个开发者协同工作并共享代码。最常见的远程仓库托管服务包括 GitHub、GitLab 和 Bitbucket。
-
拉取(Pull)和推送(Push):开发者可以从远程仓库拉取最新的更改以更新本地代码,也可以将本地更改推送到远程仓库以共享他们的工作。
-
合并(Merge)和解决冲突:当多个开发者在同一文件的相同部分进行更改时,Git 可能会产生冲突。开发者需要解决这些冲突,然后进行合并操作以保持代码的一致性。
-
标签(Tags):Git 允许您为特定的提交创建标签,通常用于标记版本。标签可以帮助开发者快速找到重要的项目里程碑。
1.1 Git安装
在Windows上使用Git,先从Git官网直接下载安装程序,选择指定系统下载,然后按默认选项安 装即可。安装完成后,在开始菜单里找到“Git”->“Git Bash”,显示出类似命令行的窗口,说明Git安装成功!
接着需要设置一下机器信息,这台机器上的所有Git仓库都会使用这个配置
git config --global user.name "your_username"
git config --global user.email your_email@domain.com
git config --list 查看所有配置
1.2 创建 Git 仓库
版本库又名仓库,可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来, 每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可 以“还原”。
创建 Git 仓库
要开始使用 Git 来跟踪项目,需要将项目目录初始化为一个 Git 仓库。
# 在项目目录中执行以下命令
git init
初始化了一个空的仓库,目录下多了.git目录
系统自动创建了唯一一个master分支
版本控制系统只能跟踪文本文件的改动,且编码方式是utf-8
添加文件
将项目中的文件添加到 Git 跟踪列表,以便开始监控它们的更改。
# 添加单个文件
git add filename
# 添加所有文件和文件夹
git add .
提交更改
一旦您添加了要跟踪的文件,您可以提交它们,创建一个新的快照并附上描述信息。
git commit -m "Your commit message"
-m后面输入的是本次提交的说明,提交成功后会显示:
1 file changed
:1个文件被改动(我们新添加的readme.txt文件);
2 insertions
:插入了两行内容(readme.txt有两行内容)。
commit
可以一次提交很多文件,所以你可以多次add
不同的文件
git add file1.txt
git add file2.txt file3.txt
git commit -m "add 3 files."
如果提交的备注写错了,可以用以下命令修改刚刚提交的备注
git commit --amend
查看状态
您可以使用以下命令查看项目的状态,包括已修改、已暂存和未跟踪的文件。
git status
查看提交历史
您可以使用以下命令查看项目的提交历史记录。
git log
git log显示最近到最远的提交日志
git的版本号是用SHA1计算出来的一个16进制数
如果嫌输出信息太多,可以加上--pretty=oneline
回退历史版本
git reset
首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD
表示当前版本,也就是最新的提交1094adb...
,上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^
比较容易数不过来,所以写成HEAD~100
。
git reset
主要有三种模式:--soft
、--mixed
和 --hard
,它们分别用于不同的情况和目的。
git reset --soft
:
- 这个模式用于将分支指针和 HEAD 移动到旧的提交,但不更改工作目录或暂存区的内容。
- 通过
--soft
模式,您可以取消先前的提交,将文件更改放回到暂存区,然后重新提交。 - 这对于在撤销不正确的提交或重新整理提交历史时非常有用。
git reset --soft HEAD~1 # 撤销最后一个提交,但保留更改在暂存区
git reset --mixed
:
- 这个模式是默认模式,它将分支指针和 HEAD 移动到旧的提交,并将文件更改放回工作目录,但不影响暂存区。
- 通过
--mixed
模式,您可以取消先前的提交,并将更改放回工作目录,然后可以选择重新暂存并提交这些更改。 - 这对于重新审查和修改提交历史非常有用。
git reset --mixed HEAD~1 # 撤销最后一个提交,并将更改放回工作目录
git reset --hard
:
- 这个模式将分支指针和 HEAD 移动到旧的提交,完全重置工作目录、暂存区和文件内容为旧提交的状态。
- 使用
--hard
模式会永久删除未提交的更改,谨慎使用,因为无法恢复删除的更改。 - 这对于完全取消提交,或将分支指针移回到过去的状态非常有用。
git reset --hard HEAD~1 # 撤销最后一个提交,并删除未提交的更改
git reset <commit>
:
除了使用 HEAD~<number>
形式的相对引用,您还可以使用具体的提交哈希或分支名作为参数来移动分支指针。
git reset abc123 # 将分支指针移动到具体的提交(abc123)
git reset main # 将分支指针移动到分支(main)的最新提交
git reset --hard origin/main
:
在与远程仓库同步时,您可以使用此命令将本地分支完全重置为远程分支的状态。这对于解决冲突或重新同步分支非常有用。
git reset --hard HEAD^
:
HEAD^
表示前一个提交,这可以用于快速撤销最后一次提交。
查看历史命令
要是不记得刚才的版本号了,可以使用以下命令:
git reflog
Git工作区和暂存区
工作区(Working Directory):指的是在电脑里能看到的目录,比如mymenu文件夹就是一个工作区
版本库(Repository):.git目录,Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
git add是把需要提交的文件添加到暂存区
git commit是把暂存区的所有内容提交到当前分支
分支管理
创建分支
要创建新的分支,您可以使用以下命令。分支用于并行开发、特性工作等。
git branch new-branch-name
切换分支
要切换到不同的分支,您可以使用以下命令。
git checkout branch-name
git checkout
命令加上-b
参数表示创建并切换,相当于以下两条命令:
git branch new-branch-name
git checkout branch-name
查看分支
用git branch
命令查看当前分支:
$ git branch
* dev
master
git branch
命令会列出所有分支,当前分支前面会标一个*
号。
合并分支
当您完成分支上的工作并希望将更改合并回主分支时,可以使用以下命令。
git checkout main # 切换回主分支
git merge branch-name # 将分支合并到主分支
每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master
分支。HEAD
严格来说不是指向提交,而是指向master
,master
才是指向提交的,所以,HEAD
指向的就是当前分支。
一开始的时候,master
分支是一条线,Git用master
指向最新的提交,再用HEAD
指向master
,就能确定当前分支,以及当前分支的提交点:
每次提交,master
分支都会向前移动一步,这样,随着你不断提交,master
分支的线也越来越长。
当我们创建新的分支,例如dev
时,Git新建了一个指针叫dev
,指向master
相同的提交,再把HEAD
指向dev
,就表示当前分支在dev
上:
Git创建一个分支很快,因为除了增加一个dev
指针,改改HEAD
的指向,工作区的文件都没有任何变化。
不过,从现在开始,对工作区的修改和提交就是针对dev
分支了,比如新提交一次后,dev
指针往前移动一步,而master
指针不变:
假如我们在dev
上的工作完成了,就可以把dev
合并到master
上。Git怎么合并呢?最简单的方法,就是直接把master
指向dev
的当前提交,就完成了合并:
所以Git合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除dev
分支。删除dev
分支就是把dev
指针给删掉,删掉后,我们就剩下了一条master
分支:
解决冲突
如果多个分支在同一文件的同一部分进行了更改,会发生冲突。在合并时,Git 无法自动解决这些冲突,需要手动解决冲突并提交解决方案。
删除分支
使用 git branch -d <branch-name>
命令可以删除分支。如果要删除未合并的分支,可以使用 -D
选项。
git branch -d feature-branch # 删除特性分支(已合并)
git branch -D feature-branch # 强制删除特性分支(未合并)
远程分支
Git 支持远程分支,它们是存储在远程仓库中的分支。可以使用 git fetch
和 git pull
从远程获取分支,并使用 git push
推送您的更改到远程分支。
git fetch origin # 从远程获取分支信息
git checkout origin/feature-branch # 切换到远程分支
git push origin feature-branch # 推送本地分支到远程
分支策略
开发团队通常会制定分支策略,例如使用主分支进行生产发布、使用开发分支进行日常开发、使用特性分支开发新功能等。这有助于组织和管理开发工作。
标签(Tags)
标签是一个用于标记特定提交的不可变引用。它们通常用于标识版本或重要的里程碑。
新建一个标签(默认为HEAD
,也可以指定一个commit id)
git tag <标签名>
git tag <标签名> <commit id>
git tag -a <标签名> -m "备注"
创建带有说明的标签,用-a
指定标签名,-m
指定说明文字
查看标签
标签不是按时间顺序列出,而是按字母排序的。
git tag查看所有标签,用git show 标签名查看指定的某个标签信息
git tag
git show <标签名>
二、移动端开发
前端开发分类
-
PC端开发:页面主要运行在PC端浏览器中
- 移动web开发
在移动端表现良好的页面,如新浪网
- 混合式开发(Hybrid App)
也叫“套壳开发”,通过写特定的代码生成跨平台的web app,可以用一些前端native开发框架或者是在移动端网页的基础上打包生成app。
- 移动端web app开发
前端开发平台
- 前端开发平台主要是指web平台和移动设备平台,移动设备平台又可分为andriod平台、iPhone平台等
- 每个平台都有自己的规范和开发技术
- web平台的规范是键盘+鼠标,开发技术是html+css+javascript
- 移动设备平台的规范是键盘+手指(触摸和手势),iphone技术是Objective-C,android是java
移动端web开发基础
1.物理像素
物理像素(physical pixel)也可成为设备像素(dp:device pixel),显示屏是由一个个物理像素点组成的,通过控制每个像素点的颜色,使屏幕显示出不同的图像,其与设备有关,不可改变。实际开发中不用,其单位为pt
2.CSS像素
- CSS像素又称逻辑像素(logical pixel)或设备独立像素(dip:device independent pixel),它与设备无关,是实际开发中使用的像素,其单位为px
- 物理像素和CSS像素的缩小放大
3.设备像素比
设备像素比(dpr:device pixel ratio),即dpr = 设备像素 / CSS像素(缩放比是1的情况下)
标清屏幕:dpr=1;
高清屏幕:dpr>=2
4.缩放问题
缩放改变的是CSS像素的大小
按照以上的物理像素比,对于一张50px * 50px 的图片,在手机打开时就会放大倍数,这将会造成图片模糊。在标准的viewport设置中,使用多倍图来提高图片质量,解决高清设备中的模糊问题。通常采用的是二倍图。
- 多倍图用法:一般要显示一张50px *50px 的图像时,首先需要准备一张100px * 100px 的原始高清图片,在css样式中设置宽高为原始的一半即可;
- 二倍精灵图做法:首先将精灵图整体等比例缩放为原来的一半,之后根据新图的大小测量偏移坐标。然后再将background-size的值也改为原始的一半
5.PPI
- 分辨率就是屏幕图像的精密度,是指显示器所能显示的像素的多少。由于屏幕上的点、线和面都是由像素组成的,显示器可显示的像素越多,画面就越精细,同样的屏幕区域内能显示的信息也越多,所以分辨率是个非常重要的性能指标之一
- PPI是每英寸的物理像素点
- ppi:pixels per inch
- dpi:dots per inch
6.视口viewport
视口在PC端是指浏览器显示页面内容的屏幕区域;视口在移动端视口分为三个:
- 布局视口:移动设备的浏览器都默认设置了一个布局视口,一般将视口分辨率设置为980px,使得PC端的网页能够在手机上呈现。
在桌面浏览器中,布局视口通常很大,以适应网页的内容。
在移动设备上,布局视口可能较小,因为屏幕较小,但通常会自动调整以适应屏幕大小。
- 视觉视口:用户正在看到的网站区域,可通过缩放来操作视觉视口,但不会影响布局视口,布局视口仍然保持原始的大小;当进行放大操作时,视觉视口会变小
- 理想视口:理想视口是为了让网站在移动端有最理想的浏览和阅读宽度而定。设备的理想视口就是最理想的视口尺寸,即屏幕分辨率的值。一般,布局视口的尺寸不是理想视口,因此,需要手动添加
<meta>
视口标签来进行操作使得布局视口与理想视口一致。
<meta>
的属性
移动端常见布局
1.流式布局
- 流式布局也是百分比布局,页面中元素的宽度按照屏幕分辨率自动进行适配调整,页面中的元素大小也可以跟着改变。
- 将盒子的宽度设置成百分比,根据屏幕的实际宽度进行伸缩,不受固定像素的限制,内容向两侧填充
- 设置
max-width
,min-width
,使得内容在合理的范围内 - 该布局一般用于页面始终满屏的情况,比如京东页面;等分情况,如导航器5等分;网页布局为左右两侧固定大小,中间自适应,如圣杯布局和双飞翼布局;左侧固定大小、右侧自适应等同理
- 流式布局的缺点是:如果屏幕尺幅跨度太大,那么在相对于原始设计过大或过小的屏幕上不能正常显示,因为宽度用%定义,高度和文字还是用px固定,所以在大屏幕的手机下显示效果会变成有些页面元素宽度被拉的很长,但是高度、文字大小还是和原来一样(即,这些东西无法变得“流式”),显示非常不协调
2.弹性布局
- CSS 弹性盒子布局(Flexbox)是一种用于创建复杂布局的强大工具。它可以轻松管理网页中的项目排列和对齐。
- 弹性布局非常适合移动端开发,因为它可以轻松处理不同屏幕尺寸和方向。
- 优点:强大的布局控制,适应性强,简化了复杂布局;缺点:在某些旧浏览器中支持不完全。
3.rem自适应布局
(1)em和rem
em: 相对于当前元素的字体大小→ 1em = 当前标签的font-size
,浏览器默认的font-size
的大小为16px
rem: 相对于根元素(html)的字体大小→ 1rem = html标签的font-size
(2)rem布局的原理
- 通过媒体查询的方式动态改变html标签的
font-size
大小 - 当屏幕越大(小),让html标签的font-size变大(小)即可
(3)rem布局的优点
- rem布局,盒子适配所有的屏幕,并且可以在多个屏幕大小中完美还原设计图(等比例缩放)
等比例缩放:设计图的屏幕宽度/给设计图设置的font-size = 你需要适配的屏幕宽度/你需要适配屏幕的fong-size
4.响应式布局
响应式布局指的是同一页面在不同屏幕尺寸下有不同的布局,其适用于页面比较简单的网页,不适合复杂的网页,如电商类
响应式布局是一种通过使用媒体查询(Media Queries)来根据不同屏幕尺寸和设备特性应用不同样式和布局的技术。
响应式设计与自适应设计的区别:响应式开发一套界面,通过检测视口分辨率,针对不同客户端在客户端做代码处理,来展现不同的布局和内容;自适应需要开发多套界面,通过检测视口分辨率,来判断当前访问的设备是pc端、平板、手机,从而请求服务层,返回不同的页面。
媒体查询允许根据屏幕宽度、高度、方向、分辨率等条件来选择性地应用 CSS 样式。
响应式布局可以包括流式布局、弹性布局和 rem 自适应布局等技术,以适应不同设备的需求。
优点:高度灵活,可以根据不同设备提供不同的用户体验;缺点:需要编写更多的 CSS 代码和媒体查询。
三、模块化
前端模块化开发是一种通过将前端代码拆分为小的、可重用的模块来组织和管理前端项目的方法。这种开发方法旨在提高代码的可维护性、可扩展性和复用性,并降低开发过程中的错误和冲突。
对于一个复杂的程序,将其按照一定的规范封装成几个文件块,每一块向外暴露一些接口, 但是块的内部数据是私有的, 块与块之间通过暴露的接口进行通信,这个过程称为模块化。
一个模块具有的基本特征:
- 代码封装,避免全局污染
- 具有唯一标识
- 暴露部分数据或者api方法供外部使用
- 模块使用方便快捷
模块化演变过程
1.文件划分方式
- 将每个功能和相关的一些状态数据单独存放在不同的文件当中,此时一个文件就是一个独立的模块。然后将这个模块引入页面当中,直接调用模块中的成员(变量/函数),一个script标签就对应一个模块,所有模块都在全局范围内工作。
- 缺点:
- 污染全局作用域
- 命名冲突问题
- 无法管理模块依赖关系
2.对象封装
- 将所有模块成员封装在一个对象中,当要使用的时候就调用这个对象的属性
- 缺点:
- 没有私有空间,模块成员仍然可以在外部被访问或修改
- 无法管理模块依赖关系
3.立即执行函数
- 采用该方式为模块提供私有空间,将模块中每个成员都放在一个函数提供对的私有作用域中,可确保私有成员的安全。私有成员只能在模块成员内通过闭包的形式访问
CommonJS规范
var x = 5;
var addX = function (value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
CommonJS 是一种用于在 JavaScript 中组织和管理模块的规范,最初设计用于服务器端 JavaScript(如Node.js),但现在它在前端开发中也有广泛的应用。CommonJS 规范的主要目标是解决 JavaScript 中模块化和依赖管理的问题,使得代码更加可维护和可重用。
每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
导出模块
每个模块可以通过 module.exports
对象来导出自己的接口,其他模块可以通过 require
函数来导入这些接口。
// example.js
var x = 5;
var addX = function (value) {
return value + x;
};
上面代码中,变量x
和函数addX
,是当前文件example.js
私有的,其他文件不可见。
如果想在多个文件分享变量,必须定义为global
对象的属性。
global.warning = true;
上面代码的warning
变量,可以被所有文件读取。当然,这样写法是不推荐的。
CommonJS规范规定,每个模块内部,module
变量代表当前模块。这个变量是一个对象,它的exports
属性(即module.exports
)是对外的接口。加载某个模块,其实是加载该模块的module.exports
属性。
var x = 5;
var addX = function (value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
上面代码通过module.exports
输出变量x
和函数addX
。
导入模块
使用 require
函数来导入其他模块的接口。
var example = require('./example.js');
console.log(example.x); // 5
console.log(example.addX(1)); // 6
Module对象
Node内部提供一个Module
构建函数。所有模块都是Module
的实例。
function Module(id, parent) {
this.id = id;
this.exports = {};
this.parent = parent;
// ...
每个模块内部,都有一个module
对象,代表当前模块。它有以下属性。
module.id
模块的识别符,通常是带有绝对路径的模块文件名。module.filename
模块的文件名,带有绝对路径。module.loaded
返回一个布尔值,表示模块是否已经完成加载。module.parent
返回一个对象,表示调用该模块的模块。module.children
返回一个数组,表示该模块要用到的其他模块。module.exports
表示模块对外输出的值。
// example.js
var jquery = require('jquery');
exports.$ = jquery;
console.log(module);
执行这个文件,命令行会输出如下信息。
{
id: '.',
path: 'C:\\Users\\33957\\Documents\\React\\001\\my-app\\src',
exports: { '$': [Function (anonymous)] },
filename: 'C:\\Users\\33957\\Documents\\React\\001\\my-app\\src\\test.js',
loaded: false,
children: [
{
id: 'C:\\Users\\33957\\node_modules\\jquery\\dist\\jquery.js',
path: 'C:\\Users\\33957\\node_modules\\jquery\\dist',
exports: [Function (anonymous)],
filename: 'C:\\Users\\33957\\node_modules\\jquery\\dist\\jquery.js',
loaded: true,
children: [],
paths: [Array]
}
],
paths: [
'C:\\Users\\33957\\Documents\\React\\001\\my-app\\src\\node_modules',
'C:\\Users\\33957\\Documents\\React\\001\\my-app\\node_modules',
'C:\\Users\\33957\\Documents\\React\\001\\node_modules',
'C:\\Users\\33957\\Documents\\React\\node_modules',
'C:\\Users\\33957\\Documents\\node_modules',
'C:\\Users\\33957\\node_modules',
'C:\\Users\\node_modules',
'C:\\node_modules'
]
}
如果在命令行下调用某个模块,比如node something.js
,那么module.parent
就是null
。如果是在脚本之中调用,比如require('./something.js')
,那么module.parent
就是调用它的模块。利用这一点,可以判断当前模块是否为入口脚本。
module.exports属性
module.exports
属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports
变量。
exports变量
为了方便,Node为每个模块提供一个exports变量,指向module.exports。这等同在每个模块头部,有一行这样的命令。
var exports = module.exports;
造成的结果是,在对外输出模块接口时,可以向exports对象添加方法。
exports.area = function (r) {
return Math.PI * r * r;
};
exports.circumference = function (r) {
return 2 * Math.PI * r;
};
注意,不能直接将exports变量指向一个值,因为这样等于切断了exports
与module.exports
的联系。
exports = function(x) {console.log(x)};
上面这样的写法是无效的,因为exports
不再指向module.exports
了。
下面的写法也是无效的。
exports.hello = function() {
return 'hello';
};
module.exports = 'Hello world';
上面代码中,hello
函数是无法对外输出的,因为module.exports
被重新赋值了。
这意味着,如果一个模块的对外接口,就是一个单一的值,不能使用exports
输出,只能使用module.exports
输出。
module.exports = function (x){ console.log(x);};
如果你觉得,exports
与module.exports
之间的区别很难分清,一个简单的处理方法,就是放弃使用exports
,只使用module.exports
。
require命令
1.基本用法
Node使用CommonJS模块规范,内置的require
命令用于加载模块文件。
require
命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。
// example.js
var invisible = function () {
console.log("invisible");
}
exports.message = "hi";
exports.say = function () {
console.log(message);
}
运行下面的命令,可以输出exports对象。
var example = require('./example.js');
example
// {
// message: "hi",
// say: [Function]
// }
如果模块输出的是一个函数,那就不能定义在exports对象上面,而要定义在module.exports
变量上面。
module.exports = function () {
console.log("hello world")
}
require('./example2.js')()
上面代码中,require命令调用自身,等于是执行module.exports
,因此会输出 hello world。
2.加载规则
require
命令用于加载文件,后缀名默认为.js
。
var foo = require('foo');
// 等同于
var foo = require('foo.js');
根据参数的不同格式,require
命令去不同路径寻找模块文件。
- 如果参数字符串以“/”开头,则表示加载的是一个位于绝对路径的模块文件。比如,
require('/home/marco/foo.js')
将加载/home/marco/foo.js
。 - 如果参数字符串以“./”开头,则表示加载的是一个位于相对路径(跟当前执行脚本的位置相比)的模块文件。比如,
require('./circle')
将加载当前脚本同一目录的circle.js
。 - 如果参数字符串不以“./“或”/“开头,则表示加载的是一个默认提供的核心模块(位于Node的系统安装目录中),或者一个位于各级node_modules目录的已安装模块(全局安装或局部安装)。
举例来说,脚本/home/user/projects/foo.js
执行了require('bar.js')
命令,Node会依次搜索以下文件。
/usr/local/lib/node/bar.js
/home/user/projects/node_modules/bar.js
/home/user/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js
这样设计的目的是,使得不同的模块可以将所依赖的模块本地化。
- 如果参数字符串不以“./“或”/“开头,而且是一个路径,比如
require('example-module/path/to/file')
,则将先找到example-module
的位置,然后再以它为参数,找到后续路径。 - 如果指定的模块文件没有发现,Node会尝试为文件名添加
.js
、.json
、.node
后,再去搜索。.js
件会以文本格式的JavaScript脚本文件解析,.json
文件会以JSON格式的文本文件解析,.node
文件会以编译后的二进制文件解析。 - 如果想得到
require
命令加载的确切文件名,使用require.resolve()
方法。