1. 知识点
- 模块系统
- 核心模块
- 第三方模块
- 自己写的模块
- 加载规则以及加载机制
- 循环加载
- npm
- package.json
- Express
- 第三方web开发框架
- 高度封装了http模块
- 更加专注于业务,而非底层细节
- 知其所以然
- 增删改查
- 使用文件来保存数据(锻炼异步编码)
- MongoDB
- (所有方法都封装好了)
2. 反馈
- 书籍:
- 《JavaScript 高级编程》第三版
- 《JavaScript 语言精粹》
- each 与 forEach 比较
- art-template 和 jQuery 无任何关系
- each 是 art-template 的模板语法,专属的
- {{each 数组}}
- <li{{ $value }}/li>
- {{/each}} 这是 art-template 模板引擎支持的语法,只能
模板字符串中使用 - $.each(数组, function)
- $(‘div’).each(function) 一般用于遍历 jQuery 选择器选择到的伪数组实例对象
- forEach 是 EcmaScript 5 中的一个数组遍历函数,是 JavaScript 原生支持的遍历方法 可以遍历任何可以被遍历的成员
- jQuery 的 each 方法和 forEach 几乎一致
- 由于 forEach 是 EcmaScript 5 中的,所以低版本浏览器不支持
3. 复习
- 网站开发模型
- 黑盒子
- 写代码让它变得更智能
- 按照设计好的讨论供用户使用
- 在Node中使用 art-template 模板引擎
- 安装
- 加载
- templae.render()
- 客户端渲染和服务器渲染的区别
- 最少两次请求,发起ajax在客户端使用模板引擎渲染
- 客户端拿到的就是服务端已经渲染好的
- 处理留言本案例首页数据列表渲染展示
- 处理留言本案例发表留言功能
- 路径
- 设计好的请求路径
- 掌握如何解析请求路径中的查询字符串
- url.parse()
- 如何在 Node 中实现服务器重定向
- header(‘Location’,’/’)
- 301 永久重定向,浏览器会记住;搜索引擎会抓取新的内容而保留旧的网址。
- 302 临时重定向,浏览器不记忆;搜索引擎在抓取新内容的同时,也将旧的网址替换为重定向之后的网址。
Node 中的 console (REPL) 使用
4. PHP和Node比较
- PHP+Apache(默认帮你封装好了很多底层细节操作)
- 在Node中,比较偏底层,很多东西需要亲自写代码来实现。
- 在Node中,我们开启的Web服务是一个完整的黑盒子,它不像php。
- php中无论是代码还是网页,都可以直接通过web url路径来访问。
- 在Node中开启的服务器,默认是和盒子,所有资源都不允许用户来访问,用户可以访问哪些资源由具体的开发人员编写设计的代码为准。
5. Node中的模块系统
- 使用Node编写应用程序主要就是在使用:
- ECMAScript语言
- 和浏览器不一样,在Node中没有 BOM、DOM
- 核心模块
- 文件操作的fs
- http服务的http
- url路径操作模块
- path路径处理模块
- os操作系统信息
- 第三方模块
- art-template
- 必须通过npm下载才可以 使用
- 咱们自己写的模块
- 自己创建的文件
- ECMAScript语言
6. 什么是模块化
- 文件作用域
- 通信规则
- 加载 require
- 导出 export
7. CommonJS模块化规范
在Node中的JavaScript还有一个很重要的概念:模块系统。
- 模块作用域
- 使用require方法用来加载模块
- 使用exports接口对象用来导出模块成员
7.1 加载 require
- 语法:
- var 自定义变量 = require(‘模块’)
- 两个作用:
- 执行被加载模块中的代码
- 得到被加载模块中的exports导出接口对
- 导出exports
- Node中是 模块 haul作用域,默认文件中所有成员只在当前文件模块中有效
- 对于希望可以被其他模块访问的成员,我们就需要把这些公开的成员都挂载到exports接口对象中就可以了
- 导出多个成员(必须在对象中):
exports.a = 123
exports.b = 'hello'
exports.c = function(){
console.log('ccc');
}
exports.d = {
foo: 'bar'
}
- 导出单个成员(字符串、函数):
module.exports = 'hello'
以下情况会覆盖:
module.exports = 'hello'
module.exports = function(x,y){
return x+y
}
也可以这样导出多个成员:
module.exports = {
add: function(){
return x+y
},
str: 'hello'
}
- 原理解析
export 是 module.exports的一个引用:
// var module = {
// export = {}
// }
// var exports = module.exports
console.log(exports === module.exports) // => true
exports.foo = 'bar'
// 等价于
module.exports.foo = 'bar'
// return module.exports
7.2 exports 和 module.exports 的区别
- 每个模块中都有一个module 对象
- module对象中有一个exports对象
- 我们可以把需要导出的成员都挂载到module.exports接口对象中
- 也就是:module.exports.xxx=xxx的方式
- 但是每次都module.exports.xxx=xxx很麻烦,调用太多了
- 所以node为了方便,同时在每一个模块中都提供了一个成员叫:exports
- exportx ===module.exports结果为true
- 所以对于:module.exports.xxx=xxx的方式完全可以:exports.xxx=xxx
- 当一个模块需要导出单个成员时候,这个时候必须使用:module.exports=xxx的方式
- 不要使用exports = xxx,导出单个成员这种方式不管用
- 因为每个模块最终向外return的是module.exports
- 而exports只是module.exports的一个引用
- 所以即便你为exports = xx重新赋值,也不会影响module.exports
- 但是有一种赋值方式比较特殊:exports = module.exports这个用来重新建立引用关系
- 之所以让大家明白这个道理,是希望可以更灵活的去用它
- Node是一个比肩Java,php的一个平台
- JavaScript既能写前端也能写服务端
8. require方法加载规则
深入浅出Node.js(三),深入Node.js的模块机制
如果想要了解更多底层细节,可以自行参考:《深入浅出Node.js》中的额模块系统章节
- 核心模块
- 模块名
- 第三方模块
- 模块名
- 用户自己写的
- 路径
- 优先从缓存加载
main.js
require('./a')
// 优先从缓存加载
// 由于在a中已经加载过b了
// 所以这里不会重复加载
// 可以拿到其中的接口对象,但是不会重复执行加载的代码
// 这样做的目的是为了避免重复加载,提高加载效率
var fn = require('./b')
console.log(fn)
a.js
console.log('a.js被加载了')
var fn = require('./b')
console.log(fn)
b.js
console.log('b.js被加载了')
module.exports = function(){
console.log('hello b.js')
}
输出结果:
a.js被加载了
b.js被加载了
[Function]
[Function]
- 判断require模块标识
- 核心模块:
- 核心模块的本质也是文件
- 核心模块文件已经被编译到了二进制文件中了,我们只需要按照名字来加载就可以了
- require(‘fs’)
- require(‘http’)
- 第三方模块:
-
凡是第三方模块都必须通过npm来下载
-
使用的时候就可以通过require(‘包名’)的方式来进行加载才可以使用
-
不可能有任何一个第三方包和核心模块的名字是一样的
-
既不是核心模块,也不是路径形式的模块
-
先找到当前文件所处目录中的 node_modules目录
- node_modules/art-template
- node_modules/art-template/package.json 文件
- node_modules/art-template/package.json 文件中的 main 属性
- main 属性中就记录了 art-template 的入口模块
- 然后加载使用这个第三方包
- 实际上最终加载的还是文件
- 如果 package.json 文件不存在或者 main 指定的入口模块是也没有
- 则 node 会自动找该目录下的 index.js
- 也就是说 index.js 会作为一个默认备选项
- 如果以上所有任何一个条件都不成立,则会进入上一级目录中的 node_modules 目录查找
- 如果上一级还没有,则继续往上上一级查找。。。
- 如果直到当前磁盘根目录还找不到,最后报错:
- can not find module xxx
-
var template = require(‘art-template’)
-
注意:我们一个项目有且只有一个 node_modules,放在项目根目录中,这样的话项目中所有的子目录中的代码都可以加载到第三方包
-
不会出现有多个 node_modules
-
模块查找机制
- 优先从缓存加载
- 核心模块
- 路径形式的文件模块,自己定义的模块
- 第三方模块
- node_modules/art-template/
- node_modules/art-template/package.json
- node_modules/art-template/package.json main
- index.js 备选项
- 进入上一级目录找 node_modules
- 按照这个规则依次往上找,直到磁盘根目录还找不到,最后报错:Can not find moudle xxx
- 一个项目有且仅有一个 node_modules 而且是存放到项目的根目录
- 例如:我需要查找 art-template模块,这个模块已经被我安装到了项目中的node_modules中,
- 先去node_modules中找到 art-template文件夹
- 其次,在 art-template文件中找到packge.json
- 然后,在packge.json文件中找到main.js属性
- 通过main.js属性值找到找到具体的.js文件指向
- 最后,执行指向的.js文件
-
- 自己写的模块
- 核心模块:
9. npm
-
node package manager
-
npm 是JavaScript 世界的包管理工具,并且是 Node.js 平台的默认包管理工具。
-
通过 npm 可以安装、共享、分发代码,管理项目依赖关系。
-
npm网站
-
npm命令行工具
- npm的第二层含义就是一个命令行工具,只要你安装了node就已经安装了npm
- 常用命令:
-
1.npm –version 查看版本
-
2.npm install –global npm 版本升级
-
3.npm init
npm init -y可以跳过向导,快速生成 -
4.npm install
一次性把dependencies选项中的依赖项全部安装
简写:install i -
5.npm intall 包名
只下载包 -
6.npm install –save 包名
下载并保存依赖项(package.json文件中的dependencies选项)
简写:npm i -S 包名 -
7.npm uninstall 包名
只删除,如果有依赖性依然会保存
简写:npm un 包名 -
8.npm uninstall 包名 --save
删除的同时也会把依赖信息也去除
简写:npm un -S 包名 -
9.npm help
查看使用帮助 -
10.npm 命令 --help
查看指定命令的使用帮助
例如:npm uninstall --help来查看使用帮助
-
解决npm 被墙问题
- npm存储包文件的服务器在国外,有时候会被墙,速度很慢,所以我们需要解决这个问题。
- http://npm.taobao.org
- 安装淘宝的cnpm:
-
#在任意目录执行都可以
#–global表示安装到全局,而非当前目录
#–global不能省略,否则不管用
npm install –global cnpm - 接下来安装包的时候把之前的npm替换成cnpm即可
- 例如:
-
这里还是走国外的npm服务器,速度比较慢
npm install jquery
使用cnpm就会通过淘宝的服务器来下载jquery
cnpm install jquery - 如果不想安装cnpm又想使用淘宝的服务器来下载:
-
npm install jquery –registry https://registry.npm.taobao.org
- 但是每次手动添加参数很麻烦,我们可以把这个选项加入配置文件中:
-
npm config set registry https://registry.npm.taobao.org
查看 npm 配置信息: npm config list
只要经过上面命令的配置,以后所有的npm install都会默认通过淘宝的服务 器来下载。
10. package.json
-
我们建议每个项目都要有一个package.json文件(包括描述文件、就像产品说明书一样),用来记录安装的包日志
-
packjson文件是通过 npm init命令的方式自动初始化出来的
-
-
npm生成的packjson文件
-
-
如果node_modules删除了也不用担心,只需要:npm install就会自动把package.json中的dependencies中所有的依赖项都下载下来。
-
建议执行npm install包名的时候都加上–save这个选项,目的是用来保存项目依赖信息
-
例如:npm加载jquery、art-template包
-
10.1 package.json和package-lock.json
- npm5以前是不会有package-lock.json这个文件的
- npm5以后才加入了这个文件
- 当你安装包的时候,npm都会生成或者更新package-lock.json这个文件
- npm5以后的版本安装包不需要加–save参数,它会自动保存依赖信息
- 当你安装包的时候,会自动创建或者更新package-lock.json这个文件
- package-lock.json这个文件会保存node_modules中所有包的信息(版本、下载地址)
- 这样的话,重新npm install的时候速度就可以提升
- 从文件来看,有一个lock称之为锁
- 这个lock是用来锁定版本的
- 如果项目依赖了1.1.1版本
- 如果你重新install,其实会下载最新版本,而不是1.1.1
- 我们的目的就是希望可以锁住1.1.1这个版本
- 所以这个package-lock.json这个文件的另一个作用:就是锁定版本号,防止自动升级新版本
11. Express
- 原生的http在某些方面表现不足以应对我们的开发需求,所以我们就需要使用框架加快我们开发效率,框架的目的就是提高效率,让我们的代码更高度统一。
- 在Node中,有很多web开发框架,以express为主
- 官网: http://expressjs.com/
- 案 例:
// 0 安装
npm init
npm install express --save
// 1 引包
var express = require('express');
// 2 创建服务器应用程序,也就是原来的http.createServer
var app = express();
// 3 公开指定目录
// 只要这么做了以后,就可以直接通过/public/xx的方式访问public目录中的所有资源了
// 例如:
app.use('/public/',express.static('./public/'));
app.use('/node_modules/',express.static('./node_modules/'));
// 当服务器接收到get请求 / 的时候,执行回调处理函数
app.get('/',function(req,res){
res.send('hello express!')
});
// 当服务器接收到get请求 /about 的时候,执行回调处理函数
app.get('/about',function(req,res){
res.send('你好,我是express!')
});
// 注意:当访问不存在的文件路径时,express会自动返回404
// 相当于 server.listen
app.listen(3000,function(){
console.log('app is running at port 3000');
});