zoukankan      html  css  js  c++  java
  • nodejs(第三篇):nodejs中的文件模块、nodejs中的require与exports、http模块补充、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

  • 相关阅读:
    android之AlertDialog 点击其它区域自己主动消失
    leetCode191/201/202/136 -Number of 1 Bits/Bitwise AND of Numbers Range/Happy Number/Single Number
    CEF 框架使用集锦
    Qt WebEngine Debugging and Profiling
    Qt内置浏览器引擎WebEngine调试和分析方法
    QWebEngine踩坑记录
    带外(out of band)数据
    碰撞检测算法:点和矩形碰撞、点和圆形碰撞、矩形碰撞、圆形碰撞
    windows 7 安装visual studio 2019 闪退问题解决
    最小二乘法
  • 原文地址:https://www.cnblogs.com/Nicholas0707/p/12571457.html
Copyright © 2011-2022 走看看