刚为玉石 發表於 2022-2-21 21:20:00

Node.js入门

<blockquote>
<p>参考:https://lurongtao.gitee.io/felixbooks-gp19-node.js/</p>
</blockquote>
<h1 id="一node简介">一、Node简介</h1>
<h3 id="11-node是什么">1.1 Node是什么</h3>
<p>Node.js®是基于 Chrome的V8 JavaScript 引擎构建的JavaScript运行环境、运行时(runtime)。</p>
<p>Node.js不是新语言,也不是一个框架或者一个库,而是一个<strong>软件</strong>。2009出现的。</p>
<p>Node.js是一个 JavaScript <strong>运行环境</strong> ,说白了,就是用来运行js的。</p>
<p>官网:https://nodejs.org/en/</p>
<p>中文官网:https://nodejs.org/zh-cn/</p>
<h3 id="12-node能做什么">1.2. Node能做什么</h3>
<p>Node 打破了过去 JavaScript 只能在浏览器中运行的局面。前后端编程环境统一,大大降低了前后端语言切换的代价。</p>
<ul>
<li>Node.js 适合开发服务器端的中间层(BFF)</li>
<li>Node.js 适合用于开发前端方向的各种工具</li>
</ul>
<p>以下是Node可以实现的工作:(仅作了解)</p>
<ul>
<li>Web 服务器</li>
<li>命令行工具</li>
<li>网络爬虫</li>
<li>桌面应用程序开发(Electron)</li>
<li>app</li>
<li>嵌入式</li>
<li>游戏</li>
<li>......</li>
</ul>
<h3 id="13-安装node">1.3. 安装Node</h3>
<p>官网:https://nodejs.org/en/</p>
<p>中文官网:https://nodejs.org/zh-cn/</p>
<p>安装后,可打开终端如cmd,输入node -v 查看是否安装成功</p>
<h1 id="二nodejs-相关工具">二、Node.js 相关工具</h1>
<h2 id="21-nvm">2.1 nvm</h2>
<p>我们知道,NodeJS有太多的版本了,切记,并不是新版本一出现,旧的版本就不去用了。</p>
<p>在不同的项目开发过程中,可能需要我们在电脑中同时存在多个不同版本的Node。<br>
这时候就需要一个软件,来更好地管理这些不同版本地Node存在我们地电脑中,Nvm就是这样一个软件。</p>
<p>nvm (node.jsversionmanager 的简写)翻译过来 nodejs 版本管理器。</p>
<h3 id="211-安装nvm">2.1.1 安装Nvm</h3>
<p>nvm下载链接https://github.com/coreybutler/nvm-windows/releases</p>
<p><strong>注意:如果电脑之前安装过nodejs,请先卸载nodejs后再进行安装。</strong></p>
<p><strong>检测nvm是不是安装成功了:</strong></p>
<p>成功安装后,新开一个 cmd 窗口,输入 <code>nvm -v</code> 如果有信息,代表安装成功!</p>
<p><strong>配置nvm:</strong></p>
<p>复制下面两句话到nvm的安装目录的settings.txt的最后。<br>
(目的是加快后面下载nodejs的速度)</p>
<pre><code>node_mirror: https://npm.taobao.org/mirrors/node/
npm_mirror: https://npm.taobao.org/mirrors/npm/
</code></pre>
<h3 id="212-nvm命令">2.1.2 nvm命令</h3>
<ul>
<li>nvm version:         查看 nvm 的版本</li>
<li>nvm list:            查看当前安装的 Node.js 所有版本   (常用)</li>
<li>nvm install 版本号 [架构]:    安装指定版本的 Node.js(常用)</li>
<li>nvm uninstall 版本号:卸载指定版本的 Node.js</li>
<li>nvm use 版本号:      选择指定版本的 Node.js   (常用)</li>
</ul>
<pre><code># 安装指定版本
nvm install 10.15.0

# 安装最新版本
nvm install latest

# 使用安装的这个版本10.15.0
nvm use 10.15.0

# 查看node版本
node -v
</code></pre>
<h2 id="22-npm">2.2 npm</h2>
<p><code>npm</code> 全称为 <code>Node Package Manager</code>,是一个基于 <code>Node.js</code> 的包管理器,也是整个 <code>Node.js</code> 社区最流行、支持的第三方模块最多的包管理器。npm的初衷:JavaScript开发人员更容易分享和重用代码。</p>
<p><code>npm</code> 全称为 <code>Node Package Manager</code>,是一个基于 <code>Node.js</code> 的包管理器,也是整个 <code>Node.js</code> 社区最流行、支持的第三方模块最多的包管理器。npm的初衷:JavaScript开发人员更容易分享和重用代码。</p>
<ol>
<li>nodejs = ECMAScript + 核心模块</li>
<li>自己遵循 commonjs 规范写出模块,如果写的是功能模块(日期处理datejs,数字处理numberjs)。如果可以把这些模块分享出来,以后谁要进行相关功能开发的时候,直接拿开发好的模块使用即可,没必要自己在开发。在互联网有一个网站专门收集这样的工具包。https://www.npmjs.cn/。</li>
<li>如果我们要使用这个网站里面的包,则我们需要使用一个功能,叫做 npm。</li>
</ol>
<p>官网:https://www.npmjs.cn/</p>
<p>https://www.npmjs.com/</p>
<p>npm可以用来:</p>
<ul>
<li>允许用户获取第三方包并使用</li>
<li>允许用户将自己编写的包或命令行程序进行发布分享</li>
</ul>
<h3 id="221-npm安装">2.2.1 npm安装</h3>
<p><code>npm</code>不需要单独安装。在安装 <code>Node</code> 的时候,会连带一起安装<code>npm</code>。</p>
<p>执行下面的命令可以用来查看本地安装的 npm 的版本号。</p>
<pre><code class="language-bash">npm -v
</code></pre>
<p>如果想升级 npm ,可以这样</p>
<pre><code class="language-bash">npm install npm --global(-g)
</code></pre>
<h3 id="222-npm常用命令">2.2.2 npm常用命令</h3>
<ol>
<li>npm help    查看所有命令<br>
npm help xxx    查看某条命令的详细帮助</li>
<li>npm install (i) xxx    本地安装<br>
npm install (i) xxx -g    全局安装</li>
<li>npm list (ls) -g    查看所有全局安装的模块信息,list 可以简写为 ls<br>
npm list (ls) xxx    查看某个安装的模块信息</li>
<li>npm uninstall (uni) xxx    卸载模块</li>
<li>npm update xxx    更新模块</li>
<li>npm search xxx    搜索模块</li>
<li>npm init    创建模块</li>
<li>npm update&lt;package&gt;    可以把当前目录下<code>node_modules</code>子目录里边的对应模块更新至最新版本<br>
npm update &lt;package&gt; -g    全局更新</li>
<li>npm root -g查看全局包安装位置</li>
</ol>
<h3 id="223-packagejson和包的安装">2.2.3 package.json和包的安装</h3>
<pre><code class="language-bash"># package.json初始化
npm init -y

# 安装包到生产环境(用户需要安装的),默认就是这个
npm install jquery --save(-S)

# 安装包到开发环境(用户可以不安装的)
npm install lodash --save-dev(-D)

# 查看包的所有版本
npm view jquery versions

# 安装包的指定版本
npm install jquery@2.2.2

# 卸载包
npm uninstall jquery

# 查看所有本地包的最新情况
npm outdated
# ~2.0.0表示patch, ^2.0.0表示minor * 表示xx最新版本

# 更新包
npm update

# 清除缓存,--force 是强制执行
npm cache clean --force

# 查看全局包安装位置
npm root -g
</code></pre>
<h3 id="224-packagejson">2.2.4 package.json</h3>
<pre><code class="language-json">{
"name": "liwker-test", // 包名
"version": "1.0.1", // 版本号
"description": "", // 描述
"main": "index.js", // 入口文件
"scripts": { // 脚本
    "test": "echo \"Error: no test specified\" &amp;&amp; exit 1"
},
"keywords": [],
"author": "Liwker",
"license": "ISC",
"dependencies": {
    "lodash": "^4.17.21"
}
}

</code></pre>
<h3 id="225-npm-包版本符号">2.2.5 npm 包版本符号</h3>
<ul>
<li>^ : 锁定major,第一个数</li>
<li>~ : 锁定minor,第二个数</li>
<li>空 : 锁定patch,第三个数(偶数为稳定,奇数为不稳定)</li>
<li>*: 最新版本</li>
</ul>
<pre><code class="language-json">"dependencies": {
    "jquery": "^3.6.0"
}
</code></pre>
<h3 id="226-上传自己的包">2.2.6 上传自己的包</h3>
<ol>
<li>
<p>编写模块,保存为 index.js</p>
<pre><code class="language-js">exports.sayHello = function(){
return 'Hello World';
}
</code></pre>
</li>
<li>
<p>注册npm仓库账号(https://www.npmjs.com/)</p>
<pre><code class="language-bash">npm adduser

// 不是第一次登录
npm login
</code></pre>
</li>
<li>
<p>上传包</p>
<pre><code class="language-bash">npm pubish
</code></pre>
</li>
</ol>
<blockquote>
<p>可以失败的原因:</p>
</blockquote>
<ol>
<li>
<p>403 Forbidden<br>
一般是源的问题,淘宝源是不能登录的</p>
<pre><code class="language-bash"># 查看npm源
npm config get registry

# 切换npm源方法一
npm config set registry http://registry.npmjs.org

# 切换npm源方法二,需要安装nrm
nrm use npm
</code></pre>
</li>
<li>
<p>Err 400<br>
我就踩了这个坑<br>
一是在注册账号后需要邮箱的验证<br>
二是package.json中的name值也就是包的名字必须是<strong>全网唯一的</strong></p>
<p>三是包的名字<strong>不能有大写字母</strong></p>
</li>
</ol>
<p>上传好了后,可以在https://www.npmjs.com/搜到自己的包<br>
就可以 npm install 自己的包</p>
<ol start="4">
<li>
<p>卸载包</p>
<pre><code class="language-bash"># 查看当前项目引用了哪些包 :
npm ls
# 卸载包:
npm unpublish --force
</code></pre>
</li>
</ol>
<h3 id="227-npm脚本">2.2.7 npm脚本</h3>
<p>Node 开发离不开 npm,而脚本功能是 npm 最强大、最常用的功能之一。</p>
<h4 id="1-什么是-npm-脚本">1 什么是 npm 脚本?</h4>
<p>npm 允许在 package.json 文件里面,使用 scripts 字段定义脚本命令。</p>
<pre><code class="language-json">{
// ...
"scripts": {
    "build": "node build.js"
}
}
</code></pre>
<h4 id="2-执行顺序">2 执行顺序</h4>
<p>如果 npm 脚本里面需要执行多个任务,那么需要明确它们的执行顺序。</p>
<pre><code class="language-json">"scripts": {
"script1": "node script1.js",
"script2": "node script2.js"
}
</code></pre>
<p>如果是并行执行(即同时的并行执行),可以使用 <code>&amp;</code> 符号。</p>
<pre><code class="language-bash">npm run script1 &amp; npm run script2
</code></pre>
<p>如果是继发(串行)执行(即只有前一个任务成功,才执行下一个任务),可以使用 <code>&amp;&amp;</code> 符号。</p>
<pre><code class="language-bash">npm run script1 &amp;&amp; npm run script2
</code></pre>
<p>多脚也可以写在json里</p>
<pre><code class="language-json">// 并行执行
"scripts": {
"start": "node script1.js &amp; node script2.js"
}

// 串行执行
"scripts": {
"start": "node script1.js &amp;&amp; node script2.js"
}
</code></pre>
<h4 id="3-简写形式">3 简写形式</h4>
<p>常用的 npm 脚本简写形式。</p>
<pre><code>npm start 是 npm run start
npm test 是 npm run test
</code></pre>
<h4 id="4-变量">4 变量</h4>
<p>npm 脚本有一个非常强大的功能,就是可以使用 npm 的内部变量。</p>
<p>首先,通过 <code>npm_package_</code> 前缀,npm 脚本可以拿到 package.json 里面的字段。比如,下面是一个 package.json。</p>
<blockquote>
<p>注意:一定要在 npm 脚本中运行(如:npm run view)才可以,直接在命令行中运行JS(如:node view.js)是拿不到值的</p>
</blockquote>
<pre><code class="language-json">{
"name": "foo",
"version": "1.2.5",
"scripts": {
    "view": "node view.js"
}
}
</code></pre>
<p>那么,变量 npm_package_name 返回 foo,变量 npm_package_version 返回 1.2.5。</p>
<pre><code class="language-js">// view.js
console.log(process.env.npm_package_name); // foo
console.log(process.env.npm_package_version); // 1.2.5
</code></pre>
<p>上面代码中,我们通过环境变量 <strong>process.env</strong> 对象,拿到 package.json 的字段值。如果是 Bash 脚本,可以用$npm_package_name 和 $npm_package_version 取到这两个值。</p>
<h3 id="228-npm-安装-git-上发布的包">2.2.8 npm 安装 git 上发布的包</h3>
<pre><code class="language-bash"># 这样适合安装公司内部的git服务器上的项目
npm install git+https://git@github.com:***.git

# 或者以ssh的方式
npm install git+ssh://git@github.com:***.git
</code></pre>
<h3 id="229-cross-env-使用">2.2.9 cross-env 使用</h3>
<ol>
<li>cross-envs 是什么</li>
</ol>
<p>运行跨平台设置和使用环境变量的脚本</p>
<ol start="2">
<li>出现原因</li>
</ol>
<p>当您使用 NODE_ENV=production, 来设置环境变量时,大多数 Windows 命令提示将会阻塞(报错)。(异常是Windows上的Bash,它使用本机Bash。)换言之,Windows 不支持 NODE_ENV=production 的设置方式。</p>
<ol start="3">
<li>解决</li>
</ol>
<p>cross-env 使得您可以使用单个命令,而不必担心为平台正确设置或使用环境变量。这个迷你的包(cross-env)能够提供一个设置环境变量的 scripts,让你能够以 Unix 方式设置环境变量,然后在 Windows 上也能兼容运行。</p>
<ol start="4">
<li>安装</li>
</ol>
<p><code>npm install cross-env -D</code></p>
<ol start="5">
<li>使用</li>
</ol>
<pre><code class="language-json">{
"scripts": {
    "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
}
}
</code></pre>
<p>NODE_ENV环境变量将由 cross-env 设置 打印 process.env.NODE_ENV === 'production'</p>
<h2 id="23-nrm">2.3. nrm</h2>
<p>NRM(npm registry manager) npm源管理</p>
<h3 id="231-手工切换源">2.3.1 手工切换源</h3>
<h4 id="1-查看当前源">1 查看当前源</h4>
<pre><code class="language-bash">npm config get registry
</code></pre>
<h4 id="2-切换淘宝源">2 切换淘宝源</h4>
<pre><code class="language-bash">npm config set registry https://registry.npm.taobao.org
</code></pre>
<h3 id="232-nrm-管理源">2.3.2 NRM 管理源</h3>
<p>NRM (npm registry manager)是npm的镜像源管理工具,有时候国外资源太慢,使用这个就可以快速地在 npm 源间切换。</p>
<h4 id="1-安装-nrm">1 安装 nrm</h4>
<p>在命令行执行命令,<code>npm install -g nrm</code>,全局安装nrm。</p>
<h4 id="2-使用-nrm">2 使用 nrm</h4>
<p>执行命令 <code>nrm ls</code> 查看可选的源。 其中,带<strong>*</strong>的是当前使用的源,上面的输出表明当前源是官方源。</p>
<pre><code>如果安装成功,执行不起,显示:path.js:39 throw new ERR_INVALID_ARG_TYPE(‘path‘, ‘string‘, path)
解决问题:
1、运行,npm ls命令,找到npm的安装路径。

2、在资源管理器中,找到nrm的安装目录,一般是:C:\Users\Administrator\AppData\Roaming\npm\node_modules\nrm

3、在目录下找到cli.js文件。

4、用文本编辑器打开它。修改里面的一行代码:

原来代码是:const NRMRC = path.join(process.env.HOME, '.nrmrc');
修改为:const NRMRC = path.join(process.env.USERPROFILE, '.nrmrc');

5、重新运行,nrm ls成功。
</code></pre>
<h4 id="3-切换-nrm">3 切换 nrm</h4>
<p>如果要切换到taobao源,执行命令 <code>nrm use taobao</code></p>
<h4 id="4-测试速度">4 测试速度</h4>
<p>你还可以通过 <code>nrm test</code> 测试相应源的响应时间。</p>
<pre><code class="language-bash">nrm test
</code></pre>
<h2 id="24-npx">2.4 npx</h2>
<p>npx: npm package extention</p>
<p>npm 从5.2版开始,增加了 npx 命令。它有很多用处,本文介绍该命令的主要使用场景。</p>
<p>Node 自带 npm 模块,所以可以直接使用 npx 命令。万一不能用,就要手动安装一下。</p>
<pre><code class="language-bash">npm install -g npx
</code></pre>
<h3 id="241-调用项目安装的模块">2.4.1 调用项目安装的模块</h3>
<p>npx 想要解决的主要问题,就是调用项目内部安装的模块。比如,项目内部安装了Mocha。</p>
<pre><code class="language-bash">npm install -D mocha
</code></pre>
<p>一般来说,调用 Mocha ,只能在项目脚本和 package.json 的scripts字段里面,如果想在命令行下调用,必须像下面这样。</p>
<pre><code class="language-bash"># 项目的根目录下执行
node-modules/.bin/mocha --version
</code></pre>
<p>npx 就是想解决这个问题,让项目内部安装的模块用起来更方便,只要像下面这样调用就行了。</p>
<pre><code class="language-bash">npx mocha --version
</code></pre>
<p>npx 的原理很简单,就是运行的时候,会到node_modules/.bin路径和环境变量$PATH里面,检查命令是否存在。</p>
<p>由于 npx 会检查环境变量$PATH,所以系统命令也可以调用。</p>
<pre><code class="language-bash"># 等同于 ls
npx ls
</code></pre>
<p>注意,Bash 内置的命令不在$PATH里面,所以不能用。比如,cd是 Bash 命令,因此就不能用npx cd。</p>
<h3 id="242----no-install-参数和---ignore-existing-参数">2.4.2--no-install 参数和 --ignore-existing 参数</h3>
<p>如果想让 npx 强制使用本地模块,不下载远程模块,可以使用<code>--no-install</code>参数。如果本地不存在该模块,就会报错。</p>
<pre><code class="language-bash">npx --no-install http-server
</code></pre>
<p>反过来,如果忽略本地的同名模块,强制安装使用远程模块,可以使用<code>--ignore-existing</code>参数。比如,本地已经安装了http-server,但还是想使用远程模块,就用这个参数。</p>
<pre><code class="language-bash">npx --ignore-existing http-server
</code></pre>
<h2 id="25-noddmon">2.5 noddmon</h2>
<p>在使用node的一些比如http模块写web服务器,但是每次改写一点代码都需要重启服务器,开发不是很方便。nodemon可以监听代码的改动自动更新,不需要重启服务器程序就可以看效果。</p>
<p>文档:https://www.npmjs.com/package/nodemon</p>
<p>下载:</p>
<pre><code class="language-bash">npm install -g nodemon
</code></pre>
<h2 id="26-相关文档">2.6 相关文档</h2>
<ul>
<li>
<p>http://www.ruanyifeng.com/blog/2019/02/npx.html</p>
</li>
<li>
<p>npm 模块管理器</p>
</li>
<li>
<p>npm 模块安装机制</p>
</li>
<li>
<p>nrm</p>
</li>
<li>
<p>http://www.ruanyifeng.com/blog/2019/02/npx.html</p>
</li>
<li>
<p>https://github.com/zkat/npx</p>
</li>
<li>
<p>https://www.jianshu.com/p/cee806439865</p>
</li>
</ul>
<h1 id="三模块包-与commonjs">三、模块/包 与CommonJS</h1>
<p>Node.js 有三类模块,即内置的模块、第三方的模块、自定义的模块。</p>
<h3 id="3-1-内置的模块">3. 1 内置的模块</h3>
<p>Node.js 内置模块又叫核心模块,Node.js安装完成可直接使用。如:</p>
<pre><code class="language-js">const path = require('path')
var extname = path.extname('index.html')
console.log(extname)
</code></pre>
<h3 id="32-第三方的nodejs模块">3.2 第三方的Node.js模块</h3>
<p>第三方的Node.js模块指的是为了实现某些功能,发布的npmjs.org上的模块,按照一定的开源协议供社群使用。如:</p>
<pre><code>npm install chalk
const chalk = require('chalk')
console.log(chalk.blue('Hello world!'))
</code></pre>
<h3 id="33-自定义的nodejs模块">3.3 自定义的Node.js模块</h3>
<p>自定义的Node.js模块,也叫文件模块,是我们自己写的供自己使用的模块。同时,这类模块发布到npmjs.org上就成了开源的第三方模块。</p>
<p>自定义模块是在运行时动态加载,需要完整的路径分析、文件定位、编译执行过程、速度相比核心模块稍微慢一些,但是用的非常多。</p>
<h4 id="331-模块定义接口暴露和引用接口">3.3.1 模块定义、接口暴露和引用接口</h4>
<p>我们可以把公共的功能 抽离成为一个单独的 js 文件 作为一个模块,默认情况下面这个模块里面的方法或者属性,外面是没法访问的。如果要让外部可以访问模块里面的方法或者属性,就必须在模块里面通过 exports 或者 module.exports 暴露属性或者方法。</p>
<p>m1.js:</p>
<pre><code class="language-js">const name = 'Liwker'

const sayName = () =&gt; {
console.log(name)
}

console.log('module 1')

// 接口暴露方法一:
module.exports = {
say: sayName
}

// 接口暴露方法二:
exports.say = sayName

// exports是对 module.exports 的引用
// 相当于 exports = module.exports

// 所以下面这种是错误的!
/*
    exports = {
      say: sayName
    }
*/
</code></pre>
<p>main.js:</p>
<pre><code class="language-js">// 引用模块
const m1 = require('./m1.')
m1.say()
</code></pre>
<h1 id="四常用内置模块">四、常用内置模块</h1>
<h1 id="三-全局对象-global">三、 全局对象 global</h1>
<p>JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。</p>
<p>在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 global 对象的属性。</p>
<p>后面看到所有的全局变量,例如 console,setTimeout 和 process 是 global 变量的成员。我们甚至可以向全局变量添加成员,使其在任何地方都可用。</p>
<pre><code class="language-js">// 1. nodejs 里面声明的变量,并不会被挂载带 global 全局对象
let b = 20;
console.log(global.b);//undefined


// 2. 可以向global添加成员,使其在任何地方都可用
global.a = 10;
console.log(a); //10

// 3. 在nodejs执行js文件的过程中,里面也存在 this ,但是这个 this 和 global 并不是相等。
console.log(global === this);//false

// 实际上,在 nodejs 里面的this代表的当前这个 js模块(暂且认为 this 代表当前这个js文件)
</code></pre>
<p>process 对象</p>
<pre><code class="language-js">console.log(process.argv);
// 返回一个数组,前两个值是 node 命令所在位置,被执行 JS 文件的路径,若你执行命令时还有带有参数,依次会填充到此数组中也打印出来。(使用 nodejs 开发命令行的应用,需要获取 命令行的参数,才用得上)

console.log(process.argv.slice(2));
node process.js argv1 argv2
// 打印命令里的后两个参数


console.log(process.arch); // 打印系统位数 x64
</code></pre>
<h2 id="56-yarn">5.6 yarn</h2>
<p><code>Yarn</code> 是于 2016 年 10 月 由 Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具,旨在取代 npm 这种包管理工具。</p>
<p>官网:<br>
https://yarnpkg.com/en/docs</p>
<p>中文参考链接:<br>
https://yarn.bootcss.com/</p>
<p><strong>特点</strong>:</p>
<ul>
<li>
<p>速度超快<br>
yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大化资源利用率,因此安装速度更快。</p>
</li>
<li>
<p>超级安全<br>
在执行代码之前,yarn 会通过算法校验每个安装包的完整性。</p>
</li>
<li>
<p>超级可靠<br>
使用详细、简洁的锁文件格式和明确的安装算法,yarn 能够保证在不同系统上无差异的工作。</p>
</li>
</ul>
<p><strong>安装</strong>:</p>
<p>管理员模式运行cmd   :<code>npm install -g yarn</code></p>
<p><strong>常用命令</strong>:</p>
<table>
<thead>
<tr>
<th>npm</th>
<th>yarn</th>
</tr>
</thead>
<tbody>
<tr>
<td>npm init -y</td>
<td>yarn init -y</td>
</tr>
<tr>
<td>npm install 包名 [--save]</td>
<td>yarn add 包名</td>
</tr>
<tr>
<td>npm uninstall react [--save]</td>
<td>yarn remove </td>
</tr>
<tr>
<td>npm install react --save-dev</td>
<td>yarn add react --dev</td>
</tr>
<tr>
<td>npm update [--save]</td>
<td>yarn upgrade</td>
</tr>
<tr>
<td>npm install -g @vue/cli</td>
<td>yarn global add @vue/cli</td>
</tr>
</tbody>
</table>
<p><strong>yarn 全局安装后,命令不生效</strong></p>
<p>背景:</p>
<ol>
<li>执行 <code>yarn global add @vue/cli</code> 后,重启 <code>bash......</code>, vue 命令依然不生效</li>
<li>而 npm 全局安装(npm install -g @vue/cli)后,命令生效</li>
</ol>
<p>解决办法:</p>
<p>1.执行如下命令,得出 yarn 全局安装的命令所处的安装目录</p>
<pre><code class="language-shell">yarn global bin
</code></pre>
<p>2.复制安装目录至电脑的环境变量中<br>
<img src="https://img-blog.csdnimg.cn/2018110718150477.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTY0MzEzMw==,size_16,color_FFFFFF,t_70" alt="" loading="lazy"></p>
<p><strong>修改yarn全局安装路径</strong></p>
<ol>
<li>改变 yarn 全局安装位置</li>
</ol>
<pre><code class="language-shell">#1.改变 yarn 全局安装位置
yarn configset global-folder "你的磁盘路径"
#这里是我的路径
yarn configset global-folder "D:\tools\Yarn\Data"
</code></pre>
<ol start="2">
<li>改变 yarn 缓存位置</li>
</ol>
<pre><code class="language-shell">#2. 改变 yarn 缓存位置
yarn config set cache-folder "你的磁盘路径"
#这里是我的路径
yarn config set cache-folder "D:\tools\Yarn\Cache"
</code></pre>
<ol start="3">
<li>改变yarn bin位置<br>
在我们使用全局安装包的时候,会在 “D:\tools\Yarn\Data” 下 生成 <code>node_modules\.bin</code> 目录</li>
</ol>
<pre><code class="language-shell">#3.改变 yarn bin位置
yarn config set prefix "你的磁盘路径"
#这里是我的路径
yarn config set prefix "D:\tools\Yarn"
#安装全局包后,会在设置的路径下生成一个bin文件夹
</code></pre>
<p>我们需要将 <code>D:\tools\Yarn\bin</code> 整个目录 添加到系统环境变量中去,否则通过yarn 添加的全局包 在cmd 中是找不到的。</p>
<p>检查当前yarn 的 bin的 位置</p>
<pre><code class="language-shell">yarn global bin
#如果按上面设置好了的就会是 "D:\tools\Yarn\bin"
</code></pre>
<p>检查当前 yarn 的 全局安装位置</p>
<pre><code class="language-shell">yarn global dir
#如果按上面设置好了的就会是 "D:\tools\Yarn\Data"
</code></pre>
<h1 id="四模块-使用">四、模块 使用</h1>
<h2 id="41-模块规范定义">4.1 模块规范定义</h2>
<p>模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。</p>
<p>模块化的优势有以下几点:</p>
<ol>
<li>防止命名冲突</li>
<li>代码复用</li>
<li>高维护性</li>
</ol>
<p>一个js文件就是一个模块,模块的作用域是<mark>私有的</mark>,内部定义的变量或者函数,只在当前的文件(模块)可以使用</p>
<p>如果别人需要使用我们模块里面的东西,那么有两点要做(以CommonJS 的 Modules 规范:    Node.js为例)</p>
<ol>
<li>自己编写的模块,由于模块作用域是私有的,默认情况下,外部是没办法使用的;如果希望别人可以使用,则需要导出<code>exports</code> 或者 <code>module.exports</code>。 导出的时候,以对象的方式进行导出</li>
<li>别人要使用某个模块,则需要先引入该模块,使用 <code>require</code> 引入,引入后需要使用一个变量来接收导入的对象。</li>
</ol>
<p>对书写格式和交互规则的详细描述,就是模块定义规范(Module Definition Specification):</p>
<ul>
<li>AMD 规范:                  Require.js</li>
<li>CMD 规范:                  Sea.js</li>
<li>CommonJS 的 Modules 规范:    NodeJs</li>
<li>ES6 模块化规范   import ...from...</li>
</ul>
<h2 id="42-nodejs-模块化使用">4.2 NodeJs 模块化使用</h2>
<p>导出数据方式一:</p>
<pre><code class="language-js">exports.num = num;
exports.sum = sum;
exports.Animal = Animal;
</code></pre>
<p>导出数据方式二:</p>
<pre><code class="language-js">// 通过module.exports 等于一个对象,来导出数据
// 对象可采用es6简化对象的写法
module.exports = {
    num,
    sum,
    Animal
};
</code></pre>
<p>导入数据:</p>
<pre><code class="language-js">// 注意1: 如果要使用某个模块里面的数据,则需要使用 require 关键字进行导入。
// 注意2:在导入用户自己开发的模块的时候,需要加上路径(1. 相对路径(多) 2. 绝对路径) 注意: ./ 必须写上
// 注意3:模块文件的扩展名(后缀名)可以写,也可以不写
// 注意4:导出的模块一般需要使用一个变量来接收,一般把接收的量定义为常量
// 注意5: 定义常量的名称和文件的名称保持一致(这个不是必须,大家都这么做)

const m1 = require("./modules/m1.js");
</code></pre>
<p>完整代码:</p>
<pre><code class="language-js">// 导出,m1.js中:   
let num = 10;
function sum(a, b) {
    return a+b
}

class Animal{
    constructor(){
      this.age=0
    }
}

// 导出数据方式1:
// exports.num = num;
// exports.sum = sum;
// exports.Animal = Animal;


// 导出数据方式2:
// 通过module.exports 等于一个对象,来导出数据
// 对象可采用es6简化对象的写法
module.exports = {
    num,
    sum,
    Animal
};
</code></pre>
<pre><code class="language-js">//导入,使用模块
const m1 = require("./modules/m1.js");

console.log(m1);   //{ num: 10, sum: , Animal: }
console.log(m1.sum(10, 20));        // 30

const obj = new m1.Animal();
console.log(obj.age);   //        0
</code></pre>
<h2 id="43-模块里面this的指向问题">4.3 模块里面this的指向问题</h2>
<p>exports 实际上是 module.exports 的引用</p>
<p>在 nodejs 里面的 this 代表当前的这个模块,也就是 exports 对象(在文件里,不是交互终端)</p>
<pre><code class="language-js">console.log(exports);   //{}
console.log(module.exports);//{}
console.log(exports === module.exports);//trueexports实际上是module.exports的引用

console.log('this', this); // this {}

console.log(this === exports);// true
// 在 nodejs 里面的 this 代表当前的这个模块,也就是 exports 对象并且,交互模式下,没有exports这个对象
console.log(global === this );   //false    this不指向全局对象
</code></pre>
<h2 id="44-nodejs常用内置模块">4.4 nodejs常用内置模块</h2>
<p>一般项目中模块分为3种:</p>
<ol>
<li>node.js 内置模块</li>
<li>自己书写的模块</li>
<li>第三方模块(使用一个专门的工具npm进行统一管理)</li>
</ol>
<p>常用的<strong>内置模块</strong>如下:</p>
<ul>
<li>fs            :文件操作</li>
<li>http          :网络操作</li>
<li>path          :路径操作</li>
<li>querystring   :查询参数解析</li>
<li>url         :url 解析</li>
</ul>
<pre><code class="language-js">const fs = require("fs");
const http = require('http');
const path = require('path');
const querystring = require('querystring');
const url = require('url');
</code></pre>
<p>nodejs内置模块的文档网址:http://nodejs.cn/api/</p>
<h2 id="45-path-内置模块">4.5 path 内置模块</h2>
<p>path 模块,处理与路径相关</p>
<pre><code class="language-js">// 导入模块
const path = require("path");

console.log(__dirname); // 当前执行的文件绝对路径,不包含文件名

console.log(__filename);// 当前执行的文件绝对路径,包含文件名和后缀名


let extname = path.extname( __filename );   // 获取扩展名(后缀名)
console.log(extname);

let baseName = path.basename( __filename );// 获取文件名(包含后缀名)
console.log(baseName);

let dirname = path.dirname(__filename);   //获取目录(路径)
console.log(dirname);

let parse = path.parse(__filename);//获取路径字符串的对象
console.log(parse);

//路径的拼接操作 join
// join 默认相对路径的拼接 ,以当前操作系统路径分割符进行拼接
let fullPath1 = path.join('path.js');
// fullPath1 = path.join(__dirname,'path.js'); //带目录
// fullPath1 = path.join(__dirname,'a','path.js'); //带多级目录
console.log(fullPath1);
</code></pre>
<h2 id="46-buffer-数据类型">4.6 Buffer 数据类型</h2>
<p>JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。但在处理像文件流时(文件读写操作),必须使用到二进制数据。因此在 Node.js 中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。说白了,Buffer 类似于一个整数数组。</p>
<p>创建buffer对象 :</p>
<pre><code class="language-js">let buf1 = Buffer.from();//根据一个数组创建 Buffer 对象
console.log(buf1);//&lt;Buffer 61 62 63&gt; 以16进制存在buffer对象中
console.log(buf1.toString()); // abc

let buf2 = Buffer.from("nodejs");   //根据一个字符串创建 Buffer 对象
console.log(buf2);
console.log(buf2.toString());// nodejs


let buf3 = Buffer.alloc(10);   // 创建了可以存放10个字符的buffer对象
buf3.write("abc");//按照ASCII表的值,转16进制,存在buffer中
console.log(buf3);
console.log(buf3.toString());// abc

// 总结: 以后看到 &lt;Buffer .....&gt; 需要toString()   才能看到里面的真实数据
</code></pre>
<h2 id="47-fs-文件系统模块">4.7 fs 文件系统模块</h2>
<p>Node.js 的 API 内置的有两个模块: path 和 fs ,我们使用 JavaScript 代码编写程序运行在 Node.js 环境中就可以操作文件</p>
<h3 id="471-同步读取文件信息">4.7.1 同步读取文件信息</h3>
<p>同步读取:读取的时候,要等文件读取完毕后,才会执行后面的代码   (sync同步)</p>
<pre><code class="language-js">// 准备工作
const fs = require("fs");
const path = require("path");
let pathName = path.join(__dirname, 'hello.txt');

//同步读取文件
const content = fs.readFileSync(pathName);
// console.log(content);
// 转换
console.log(content.toString());

const content = fs.readFileSync(pathName, "utf-8");
console.log(content);
</code></pre>
<h3 id="472-异步读取文件信息">4.7.2 异步读取文件信息</h3>
<p>不用等待文件读取完毕就会执行后面的代码。所谓异步,就是当前回调函数不用等执行完就可以执行后面的语句。</p>
<p>思考:如何读到后面的数据</p>
<p>答:在读取文件的时候,传递一个回调函数callback,当读取完毕后,回调函数执行,读取后面的数据</p>
<pre><code class="language-js">const fs = require("fs");
const path = require("path");

let pathName = path.join(__dirname, "hello2.txt");
// console.log(file);
//参数1 要读取的文件
//参数2 设置读取到内容的编码,设置后读到的内容为字符串,如果不传则读到的数据为 buffer
//参数3 回调函数,读取完文件后执行的代码
fs.readFile(pathName, "utf-8",(error, data)=&gt;{

    // console.log(error);
    // console.log(data);

           if(error){
      console.log(error);
      return;
    }

    console.log(data);
});
</code></pre>
<h3 id="473-异步写入">4.7.3 异步写入</h3>
<pre><code class="language-js">const fs = require("fs");
const path = require("path");

let pathName = path.join(__dirname, "hello.txt");

fs.writeFile(pathName, "hello_write111", "utf-8",(error)=&gt;{
    console.log("error");
    console.log("写完啦");
});
console.log("end");
</code></pre>
<h3 id="474-几个常见方法">4.7.4 几个常见方法</h3>
<pre><code class="language-js">const fs = require("fs");
fs.renameSync(旧文件名, 新文件名);   //修改文件名
fs.readdirSync(__dirname);    //读取当前路径下的文件名列表

let str = "hello";
str.endsWith("lo");   //true是否以某字符串结尾
str.startsWith("hh");//false是否以某字符串开头
str.substring(2,4) //ll 左闭右开区间
str.substring(2) //llo从下标为2取到结束
</code></pre>
<h3 id="475-小案例">4.7.5 小案例</h3>
<p>需求:把当前文件夹的js文件的名字都添加前缀</p>
<pre><code class="language-js">const fs = require("fs");
let nameList = fs.readdirSync(__dirname);

nameList.forEach(currFileName =&gt; {
    if(currFileName.endsWith(".js")){
      fs.renameSync(currFileName, `${currFileName}`)
    }
});
</code></pre>
<p>需求:把当前文件夹的名字都删除前缀 </p>
<pre><code class="language-js">const fs = require("fs");
let nameList = fs.readdirSync(__dirname);
let str1 = ""

nameList.forEach(currFileName =&gt; {
    if(currFileName.startsWith(str1)){
      fs.renameSync(currFileName, currFileName.substring(str1.length))
    }
});
</code></pre>
<h2 id="48-http-模块">4.8 http 模块</h2>
<h3 id="481-http核心模块的使用">4.8.1 http核心模块的使用</h3>
<p>四个步骤:</p>
<ol>
<li>
<p>导入http模块</p>
</li>
<li>
<p>定义服务器程序端口</p>
</li>
<li>
<p>创建服务器对象</p>
</li>
<li>
<p>调用服务器的监听方法,让服务器监听浏览器请求</p>
</li>
</ol>
<pre><code class="language-js">// 1、导入http模块
const http = require("http");

// 2、定义服务器程序端口
const port = 8080;// 端口号:1-65535 (有些服务已经有一些默认端口 apache nginx 80 web 服务。 MySQL:3306 MongoDB:27017)
// 注意:一个端口只能被一个服务进行使用,如果这个端口被某个服务使用,其他的服务不能在使用该端口的。这个时候出现端口冲突。如何解决?答:换个端口
// 建议:1-1024 端口(有些系统服务会使用这个范围的端口),不建议程序员自己使用。一般都使用 1024 以后的端口。

// 3、创建服务器对象
const server = http.createServer((request, response)=&gt;{
    response.write("hello nodejs");// 书写响应体内容
    response.end()   //发生响应到浏览器当我们修改代码后,需要重新执行该文件,重启服务
});

// 4、调用服务器的监听方法,让服务器监听浏览器请求
server.listen(port,(error)=&gt;{
    console.log(error);
    console.log(`server is running at port ${port}`);
});
</code></pre>
<pre><code class="language-js">//如果需要解决中文乱码,需遵循http协议:
response.setHeader("Content-type","text/html;charset=utf-8");
</code></pre>
<h3 id="482-获取请求的一些信息">4.8.2 获取请求的一些信息</h3>
<pre><code class="language-js">const http = require("http");
const url = require("url");

const server = http.createServer((request, response)=&gt;{
    //如果需要解决中文乱码,需遵循http协议:
        response.setHeader("Content-type","text/html;charset=utf-8");
    console.log("------------------------------");
    // Get
    let requestUrl = request.url;// 获取本次请求的资源路径
    console.log(requestUrl);

    let method = request.method;// 获取本次请求的方式
    console.log(method);

    let obj = url.parse( requestUrl, true);// true解析成对象,false解析成字符串
    console.log(obj.query);    // 获取get请求的查询字符串   
    //localhost:8080?name=nodejs&amp;age=11   get请求

    // Post
    //当存在 post 提交数据 data 事件立马执行,postData就是提交过来的数据对象
    request.on('data',(postData) =&gt; {   // 获取post请求的请求参数
      console.log(postData.toString());
    });

    response.write("hello nodejs");// 书写响应体内容
    response.end();   //发生响应到浏览器当我们修改代码后,需要重新执行该文件,重启服务
});
</code></pre>
<h1 id="六es6模块">六、ES6模块</h1>
<h2 id="61-nodejs12版本以下是-不支持es6模块化规范的解决方案">6.1 nodejs12版本以下是 不支持ES6模块化规范的解决方案</h2>
<p>在项目目录下新建src文件夹,src文件夹下新建m1.js模块和app.js模块:</p>
<p>m1.js模块中到处数据:</p>
<pre><code class="language-js">export let name = "nodejs";
export let age = 11;
</code></pre>
<p>app.js中导入模块:</p>
<pre><code>import {name,age} from "./m1.js"
</code></pre>
<p>此时运行app.js会报错!!!   SyntaxError: Unexpected token {</p>
<p>注意:<strong>nodejs 不支持 es6 模块化规范</strong>。<br>
可以把这个代码转换一下,然后把 es6 规范转换为 commonjs 规范<br>
学语法,兼容性如何不用管,可以交给第三方的转换工具(babel-cli 和 browserify)实现</p>
<p>解决:</p>
<p>1、在项目文件夹下生成生成 package.json 文件</p>
<pre><code class="language-shell">yarn init -y 或者npm init -y
</code></pre>
<p>2、安装第三方工具:</p>
<p>在任意目录下执行,全局安装babel-cli 和 browserify:</p>
<p><strong>如果yarn没有安装成功,就用npm</strong></p>
<pre><code class="language-shell">yarn global add babel-cli browserify或者npm install babel-cli browserify -g      
</code></pre>
<p>在自己项目目录下执行:</p>
<pre><code class="language-shell">yarn add babel-preset-es2015   或者   npm install babel-preset-es2015 --save-dev
</code></pre>
<p>3、在项目根目录新建 .babelrc 文件 :</p>
<pre><code>{
"presets": [
    "es2015"
]
}
</code></pre>
<p>4、在项目目录下书写完代码后,执行:</p>
<pre><code class="language-shell">babel src -d lib
// src(源文件夹) lib(目标文件夹)
</code></pre>
<p>(如果出现babel 不是内部或者外部命令,请按照第三点最后的yarn 全局安装后,命令不生效的解决办法)</p>
<p>5、运行lib下的app.js即可   node lib\app.js</p>
<p>(记得,修改代码需要执行babel src -d lib命令后,再运行lib下的app.js)</p>
<h2 id="62-es6模块化规范语法">6.2 ES6模块化规范语法</h2>
<p>导出数据方式一:</p>
<pre><code class="language-js">//导出数据方式一:
export let name = "nodejs";
export let age = 11;
</code></pre>
<p>导出数据方式二:</p>
<pre><code class="language-js">let name = "nodejs";
let age = 11;

export {name, age}
</code></pre>
<p>针对导出数据的前两种方式的导入数据:</p>
<pre><code class="language-js">import {name,age} from "./m1.js"
</code></pre>
<p>导出数据方式三:</p>
<pre><code class="language-js">// 默认导出只能写一次
export default {name, age}
</code></pre>
<p>导入并使用数据:</p>
<pre><code class="language-js">import m3 from "./m3"
console.log(m3.name);
console.log(m3.age);
</code></pre>
<p>在es6中的默认导出的写法,允许和前面的导出方式一起写:</p>
<p>导出数据:</p>
<pre><code class="language-js">let name = "nodejs";
let age = 11;

export let email = "nodejs@163.com";

// 默认导出只能写一次
export default {name, age}
</code></pre>
<p>导入并使用数据:</p>
<pre><code class="language-js">import m3, {email} from "./m3"

console.log(m3.name);
console.log(m3.age);
console.log(email);
</code></pre><br><br>
来源:https://www.cnblogs.com/Liwker/p/15920713.html
頁: [1]
查看完整版本: Node.js入门