nodejs(第三篇):nodejs中的文件模块nodejs中的require与exportshttp模块补充JavaScript Standard Style

Posted Nicholas--Altshuler

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nodejs(第三篇):nodejs中的文件模块nodejs中的require与exportshttp模块补充JavaScript Standard Style相关的知识,希望对你有一定的参考价值。

一、nodejs中的文件模块

在nodejs中,用户自己编写的模块,称为文件模块

文件模块,则是指js文件、json文件或者是.node文件。在引用文件模块的时候后要加上文件的路径:/.../.../xxx.js表示绝对路径、./xxx.js表示相对路径(同一文件夹下的xxx.js),../表示上一级目录。如果既不加/.../、../又不加./的话,则该模块要么是核心模块,要么是从一个node_modules文件夹加载。

(1)在Node.js中,require是一个方法,只有通过require方法来加载执行多个javascript脚本文件。

自定义模块相对路径必须写 . / ,可以省略后缀名js。

demo

在同一文件夹test下,创建a.js、b.js

分别写入内容

a.js内容:

console.log(\'a start\')
require(\'./b\')
console.log(\'a end\')

b.js内容

console.log(\'b msg\')

执行a.js,输出结果

ERROR: The process "node.exe" not found.
a start
b msg
a end
[Finished in 0.5s]

分析:require加载b.js中的代码,是执行其中的代码

(2)require加载只能是执行其中的代码,模块作用域是隔离的

文件与文件之间由于是模块作用域(在Node.js中没有全局作用域的概念),模块是完全封闭的,外部无法访问内部,内部也无法范访问外部。

测试1:测试文件模块之间值是否相互影响或者被覆盖

在同一文件夹test下,创建a.js、b.js

分别写入内容

a.js内容:

var foo = \'aaa\'
console.log(\'a start\')
require(\'./b\')
console.log(\'a end\')
console.log(\'foo 的值是:\', foo)

b.js内容

console.log(\'b msg\')
var foo = \'bbb\'
console.log(\'b end\')

执行a.js,输出结果

ERROR: The process "node.exe" not found.
a start
b msg
b end
a end
foo 的值是: aaa
[Finished in 0.4s]

分析:从输出结果可以看出,引入的b.js并没有影响a.js中的foo的值,文件与文件之间模块作用域是隔离的

测试2:在被引入的文件模块中调用原文件模块里的函数

在同一文件夹test下,创建a.js、b.js

分别写入内容

a.js内容:


console.log(\'a start\')

function add(x, y) {
  return x + y
}

require(\'./b\')
console.log(\'a end\')

b.js内容

console.log(\'b msg\')
console.log(add(10, 20))
console.log(\'b end\')

执行a.js,输出结果执行报错,add is not defined,函数未被定义,无法引用原文件模块的函数

二、nodejs中的require与exports

require

require函数用于在当前模块中加载和使用别的模块,传入一个模块名,返回一个模块导出对象。模块名可使用相对路径(以./开头),或者是绝对路径(以/C:之类的盘符开头)。另外,模块名中的.js扩展名可以省略。以下是一个例子。

require 方法有两个作用:

  1. 加载文件模块并执行里面的代码
  2. 拿到被加载文件模块导出的接口对象
var foo1 = require(\'./foo\');
var foo2 = require(\'./foo.js\');
var foo3 = require(\'/home/user/foo\');
var foo4 = require(\'/home/user/foo.js\');

// foo1至foo4中保存的是同一个模块的导出对象。

另外,可以使用以下方式加载和使用一个JSON文件。

var data = require(\'./data.json\');

exports

exports对象是当前模块的导出对象,用于导出模块公有方法和属性。别的模块通过require函数使用当前模块时得到的就是当前模块的exports对象。以下例子中导出了一个公有方法。

在每个文件模块中都提供了一个对象:exports
exports 默认是一个空对象
你要做的就是把所有需要被外部访问的成员挂载到这个 exports 对象中

exports.hello = function () {
    console.log(\'Hello World!\');
};

测试

在同一文件夹test下,创建a.js、b.js

分别写入内容

a.js内容:

var bExports = require(\'./b\') //引入b文件处理模块

console.log(bExports.foo) //从require对象中接收到foo属性的值

console.log(bExports.add(10, 30))//从require对象中接收到add函数

console.log(bExports.age)  //未能接收到age属性,所以输出值是undefined

bExports.readFile(\'./a.js\')  //这里执行的是b.js的readFile函数,与fs模块中的
//readFile函数无关

console.log(\'------分割线-------\')

var fs = require(\'fs\')  //引入fs文件处理模块

fs.readFile(\'./a.js\', function (err, data) {
	//执行fs模块的readFile方法
  if (err) {
    console.log(\'读取文件失败\')
  } else {
    console.log(data.toString())
  }
})

b.js内容

var foo = \'bbb\'

// console.log(exports)

exports.foo = \'hello\'

exports.add = function (x, y) {
  return x + y
}

exports.readFile = function (path, callback) {
  console.log(\'文件路径:\', path)
}

var age = 18

// exports.age = age

function add(x, y) {
  return x - y
}

执行a.js,输出结果

ERROR: The process "node.exe" not found.
hello
40
undefined
文件路径: ./a.js
------分割线-------
var bExports = require(\'./b\') //引入b文件处理模块

console.log(bExports.foo) //从require对象中接收到foo属性的值

console.log(bExports.add(10, 30))//从require对象中接收到add函数

console.log(bExports.age)  //未能接收到age属性,所以输出值是undefined

bExports.readFile(\'./a.js\')  //这里执行的是b.js的readFile函数,与fs模块中的
//readFile函数无关

console.log(\'------分割线-------\')

var fs = require(\'fs\')  //引入fs文件处理模块

fs.readFile(\'./a.js\', function (err, data) {
	//执行fs模块的readFile方法
  if (err) {
    console.log(\'读取文件失败\')
  } else {
    console.log(data.toString())
  }
})

[Finished in 0.4s]

分析:a.js通过bExports接收b.js通过exports`对象挂载的属性和函数,没有则显示undefined

三、http模块补充

设置响应头

res.setHeader()

var http = require(\'http\')

var server = http.createServer()

server.on(\'request\', function (req, res) {
  // 在服务端默认发送的数据,其实是 utf8 编码的内容
  // 但是浏览器不知道你是 utf8 编码的内容
  // 浏览器在不知道服务器响应内容的编码的情况下会按照当前操作系统的默认编码去解析
  // 中文操作系统默认是 gbk
  // 解决方法就是正确的告诉浏览器我给你发送的内容是什么编码的
  // 在 http 协议中,Content-Type 就是用来告知对方我给你发送的数据内容是什么类型
  // res.setHeader(\'Content-Type\', \'text/plain; charset=utf-8\')
  // res.end(\'hello 世界\')

  var url = req.url

  if (url === \'/plain\') {
    // text/plain 就是普通文本
    res.setHeader(\'Content-Type\', \'text/plain; charset=utf-8\')
    //设置响应头
    res.end(\'hello 世界\')
  } else if (url === \'/html\') {
    // 如果你发送的是 html 格式的字符串,则也要告诉浏览器我给你发送是 text/html 格式的内容
    res.setHeader(\'Content-Type\', \'text/html; charset=utf-8\')
    res.end(\'<p>hello html <a href="">点我</a></p>\')
  }
})

server.listen(3000, function () {
  console.log(\'Server is running...\')
})

fs模块与http模块结合

通过网络发送文件( http结合fs发送文件中的数据):发送的并不是文件,本质上发送的是文件的内容,当浏览器收到服务器响应内容之后,就会根据Content-Type进行对应的解析处理

// 1. 结合 fs 发送文件中的数据
// 2. Content-Type
//    http://tool.oschina.net/commons
//    不同的资源对应的 Content-Type 是不一样的
//    图片不需要指定编码
//    一般只为字符数据才指定编码

var http = require(\'http\')
var fs = require(\'fs\')

var server = http.createServer()

server.on(\'request\', function (req, res) {
  // / index.html
  var url = req.url

  if (url === \'/\') {
    // 肯定不这么干
    // res.end(\'<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title></head><body><h1>首页</h1></body>/html>\')

    // 我们要发送的还是在文件中的内容
    fs.readFile(\'./resource/index.html\', function (err, data) {
      if (err) {
        res.setHeader(\'Content-Type\', \'text/plain; charset=utf-8\')
        res.end(\'文件读取失败,请稍后重试!\')
      } else {
        // data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串
        // res.end() 支持两种数据类型,一种是二进制,一种是字符串
        res.setHeader(\'Content-Type\', \'text/html; charset=utf-8\')
        res.end(data)
      }
    })
  } else if (url === \'/xiaoming\') {
    // url:统一资源定位符
    // 一个 url 最终其实是要对应到一个资源的
    fs.readFile(\'./resource/ab2.jpg\', function (err, data) {
      if (err) {
        res.setHeader(\'Content-Type\', \'text/plain; charset=utf-8\')
        res.end(\'文件读取失败,请稍后重试!\')
      } else {
        // data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串
        // res.end() 支持两种数据类型,一种是二进制,一种是字符串
        // 图片就不需要指定编码了,因为我们常说的编码一般指的是:字符编码
        res.setHeader(\'Content-Type\', \'image/jpeg\')
        res.end(data)
      }
    })
  }
})

server.listen(3000, function () {
  console.log(\'Server is running...\')
})

四、JavaScript Standard Style(Js 标准编码风格)

使用两个空格 – 进行缩进

字符串使用单引号 – 需要转义的地方除外

不再有冗余的变量 – 这是导致 大量 bug 的源头!

行首不要以 (, [, or ` 开头

这是省略分号时唯一会造成问题的地方 – 工具里已加了自动检测!

关键字后加空格 if (condition) { ... }

函数名后加空格 function name (arg) { ... }

坚持使用全等 === 摒弃 == 一但在需要检查 null || undefined 时可以使用 obj == null。

一定要处理 Node.js 中错误回调传递进来的 err 参数。

使用浏览器全局变量时加上 window 前缀 – document 和 navigator 除外

避免无意中使用到了这些命名看上去很普通的全局变量, open, length, event 还有 name。



// 当你采用了无分号的代码风格的时候,只需要注意以下情况就不会有上面的问题了:
//    当一行代码是以:
//        (
//        [
//        `
//        开头的时候,则在前面补上一个分号用以避免一些语法解析错误。
//    所以你会发现在一些第三方的代码中能看到一上来就以一个 ; 开头。
//  结论:
//    无论你的代码是否有分号,都建议如果一行代码是以 (、[、` 开头的,则最好都在其前面补上一个分号。
//    有些人也喜欢玩儿一些花哨的东西,例如可以使用 ! ~ 等。

细则

  • 使用两个空格 进行缩进
function hello (name) {
  console.log(\'hi\', name)
}
  • 除需要转义的情况外,字符串统一使用单引号
console.log(\'hello there\')
$("<div class=\'box\'>")
  • 不要留下未使用的变量
function myFunction () {
  var result = something()   // ✗ avoid
}
  • 关键字后面加空格
if (condition) { ... }   // ✓ ok
if(condition) { ... }    // ✗ avoid
  • 函数声明时括号与函数名间加空格
function name (arg) { ... }   // ✓ ok
function name(arg) { ... }    // ✗ avoid

run(function () { ... })      // ✓ ok
run(function() { ... })       // ✗ avoid
  • 始终使用 === 替代 ==

例外:obj == null 可以用来检查 null || undefined

if (name === \'John\')   // ✓ ok
if (name == \'John\')    // ✗ avoid

if (name !== \'John\')   // ✓ ok
if (name != \'John\')    // ✗ avoid
  • 字符串拼接操作符(Infix operators)之间要留空格
// ✓ ok
var x = 2
var message = \'hello, \' + name + \'!\'

// ✗ avoid
var x=2
var message = \'hello, \'+name+\'!\'
  • 逗号后面加空格
// ✓ ok
var list = [1, 2, 3, 4]
function greet (name, options) { ... }

// ✗ avoid
var list = [1,2,3,4]
function greet (name,options) { ... }
  • else 关键字要与花括号保持在同一行
// ✓ ok
if (condition) {
  // ...
} else {
  // ...
}

// ✗ avoid
if (condition) {
  // ...
}
else {
  // ...
}
  • 多行if语句的括号不能省
// ✓ ok
if (options.quiet !== true) console.log(\'done\')

// ✓ ok
if (options.quiet !== true) {
  console.log(\'done\')
}

// ✗ avoid
if (options.quiet !== true)
  console.log(\'done\')
  • 使用浏览器全局变量时加上 window. 前缀

例外: document, console , navigator

window.alert(\'hi\')   // ✓ ok
  • 不允许有连续多行的空行
// ✓ ok
var value = \'hello world\'
console.log(value)
// ✗ avoid
var value = \'hello world\'


console.log(value)
  • 对于三元运算符 ? 和 : 与他们所负责的代码处于同一行
// ✓ ok
var location = env.development ? \'localhost\' : \'www.api.com\'

// ✓ ok
var location = env.development
  ? \'localhost\'
  : \'www.api.com\'

// ✗ avoid
var location = env.development ?
  \'localhost\' :
  \'www.api.com\'
  • 每个 var 关键字单独声明一个变量
// ✓ ok
var silent = true
var verbose = true

// ✗ avoid
var silent = true, verbose = true

// ✗ avoid
var silent = true,
    verbose = true
  • 单行代码块两边加空格
function foo () {return true}    // ✗ avoid
function foo () { return true }  // ✓ ok
  • 对于变量和函数名统一使用驼峰命名法
function my_function () { }    // ✗ avoid
function myFunction () { }     // ✓ ok

var my_var = \'hello\'           // ✗ avoid
var myVar = \'hello\'            // ✓ ok
  • 不允许有多余的行末逗号
var obj = {
  message: \'hello\',   // ✗ avoid
}
  • 始终将逗号置于行末
var obj = {
  foo: \'foo\'
  ,bar: \'bar\'   // ✗ avoid
}

var obj = {
  foo: \'foo\',
  bar: \'bar\'   // ✓ ok
}
  • 点号操作符须与属性处在同一行
  console.
    log(\'hello\')  // ✗ avoid

  console
    .log(\'hello\') // ✓ ok
  • 文件末尾留一空行

  • 函数调用时标识符与括号间不留间隔

console.log (\'hello\') // ✗ avoid
console.log(\'hello\')  // ✓ ok
  • 键值对当中冒号与值之间要留空白
var obj = { \'key\' : \'value\' }    // ✗ avoid
var obj = { \'key\' :\'value\' }     // ✗ avoid
var obj = { \'key\':\'value\' }      // ✗ avoid
var obj = { \'key\': \'value\' }     // ✓ ok
  • 构造函数要以大写字母开头
function animal () {}
var dog = new animal()    // ✗ avoid

function Animal () {}
var dog = new Animal()    // ✓ ok
  • 使用数组字面量而不是构造器
var nums = new Array(1, 2, 3)   // ✗ avoid
var nums = [1, 2, 3]            // ✓ ok
  • 避免修改使用 const 声明的变量
const score = 100
score = 125       // ✗ avoid
  • 避免使用常量作为条件表达式的条件(循环语句除外)
if (false) {    // ✗ avoid
  // ...
}

if (x === 0) {  // ✓ ok
  // ...
}

while (true) {  // ✓ ok
  // ...
}
  • 同一模块有多个导入时一次性写完
import { myFunc1 } from \'module\'
import { myFunc2 } from \'module\'          // ✗ avoid

import { myFunc1, myFunc2 } from \'module\' // ✓ ok
  • 不要扩展原生对象
Object.prototype.age = 21     // ✗ avoid
  • switch 一定要使用 break 来将条件分支正常中断
switch (filter) {
  case 1:
    doSomething()    // ✗ avoid
  case 2:
    doSomethingElse()
}

switch (filter) {
  case 1:
    doSomething()
    break           // ✓ ok
  case 2:
    doSomethingElse()
}

switch (filter) {
  case 1:
    doSomething()
    // fallthrough  // ✓ ok
  case 2:
    doSomethingElse()
}
  • 不要对全局只读对象重新赋值
window = {}     // ✗ avoid
  • 不要混合使用空格与制表符作为缩进

  • 除了缩进,不要使用多个空格

const id =    1234    // ✗ avoid
const id = 1234       // ✓ ok
  • new 创建对象实例后需要赋值给变量
new Character()                     // ✗ avoid
const character = new Character()   // ✓ ok
  • 禁止使用 Function 构造器
var sum = new Function(\'a\', \'b\', \'return a + b\')    // ✗ avoid
  • 禁止使用 Object 构造器
let config = new Object()   // ✗ avoid
  • 使用 __dirname 和 __filename 时尽量避免使用字符串拼接
const pathToFile = __dirname + \'/app.js\'            // ✗ avoid
const pathToFile = path.join(__dirname, \'app.js\')   // ✓ ok
  • 不要重复声明变量
let name = \'John\'
let name = \'Jane\'     // ✗ avoid

let name = \'John\'
name = \'Jane\'         // ✓ ok
  • return 语句中的赋值必需有括号包裹
function sum (a, b) {
  return result = a + b     // ✗ avoid
}

function sum (a, b) {
  return (result = a + b)   // ✓ ok
}
  • return,throw,continue 和 break 这些语句后面的代码都是多余的
function doSomething () {
  return true
  console.log(\'never called\')     // ✗ avoid
}
  • 展开运算符与它的表达式间不要留空白
fn(... args)    // ✗ avoid
fn(...args)     // ✓ ok
  • 分号前面不留空格,后面留空格
for (let i = 0 ;i < items.length ;i++) {...}    // ✗ avoid
for (let i = 0; i < items.length; i++) {...}    // ✓ ok
  • 代码块开始之前留一个空格
if (admin){...}     // ✗ avoid
if (admin) {...}    // ✓ ok
  • 圆括号间不留空格
getName( name )     // ✗ avoid
getName(name)       // ✓ ok
  • 注释前后留空格
//comment           // ✗ avoid
// comment          // ✓ ok

/*comment*/         // ✗ avoid
/* comment */       // ✓ ok
  • 模板字符串中变量前后不加空格
const message = `Hello, ${ name }`    // ✗ avoid
const message = `Hello, ${name}`      // ✓ ok
  • 检查 NaN 的正确姿势是使用 isNaN()
if (price === NaN) { }      // ✗ avoid
if (isNaN(price)) { }       // ✓ ok

关于分号

  • 不要使用分号
window.alert(\'hi\')   // ✓ ok
window.alert(\'hi\');  // ✗ avoid
  • 不要使用 (, [, or ``` 等作为一行的开始。在没有分号的情况下代码压缩后会导致报错,而坚持这一规范则可避免出错。
// ✓ ok
;(function () {
  window.alert(\'ok\')
}())

// ✗ avoid
(function () {
  window.alert(\'ok\')
}())
// ✓ ok
;[1, 2, 3].forEach(bar)

// ✗ avoid
[1, 2, 3].forEach(bar)
// ✓ ok
;`hello`.indexOf(\'o\')

// ✗ avoid
`hello`.indexOf(\'o\')

上面的写法只能说聪明过头了

比如:

;[1, 2, 3].forEach(bar)

建议的写法是:

var nums = [1, 2, 3]
nums.forEach(bar)

参考资料

[1]https://www.jianshu.com/p/e889069b7c27

[2]https://github.com/standard/standard/blob/master/docs/RULES-zhcn.md

以上是关于nodejs(第三篇):nodejs中的文件模块nodejs中的require与exportshttp模块补充JavaScript Standard Style的主要内容,如果未能解决你的问题,请参考以下文章

nodeJS中的包

nodeJS中的包

NodeJS中安装第三方模块`Gulp`以及它的使用

nodejs第三天(核心模块与文件模块,核心模块和文件模块引入的区别,从模块外部访问模块内部,使用exports对象,npm包管理工具package.json文件,模块对象属性,将模块定义分类,npm

nodejs之fs模块

nodeJS中的包 npm install http://www.cnblogs.com/xiaohuochai/archive/2017/05/20/6882027.html