我的Vue之旅、02 ES6基础、模块、路径、IO

  • 我的Vue之旅、02 ES6基础、模块、路径、IO已关闭评论
  • 10 次浏览
  • A+
所属分类:Web前端
摘要

为什么要模块?模块化源代码能给我们带来什么好处?试想一个巨无霸网购平台,在没有模块化的情况下,如果出现bug,程序员就要在几百万行代码里调试,导致后期维护成本上升,为了解决问题,模块化按功能切分,把大问题转换成小问题,让每个模块独立运营,通过接口对外开放,让程序统一调用,降低程序出错的风险,也能方便升级模块内部的代码,不影响全局


自定义模块

为什么要模块?模块化源代码能给我们带来什么好处?

试想一个巨无霸网购平台,在没有模块化的情况下,如果出现bug,程序员就要在几百万行代码里调试,导致后期维护成本上升,为了解决问题,模块化按功能切分,把大问题转换成小问题,让每个模块独立运营,通过接口对外开放,让程序统一调用,降低程序出错的风险,也能方便升级模块内部的代码,不影响全局

我的Vue之旅、02 ES6基础、模块、路径、IO

创建模块(🍔计算器)

模拟巨无霸程序(现有两个js文件 app.js server.js)
我的Vue之旅、02 ES6基础、模块、路径、IO

如果没有模块化程序,那么server.js也想用这些功能的时候也必须将函数写一遍。就会出现代码重叠,如果要修改,就要全部进行修改
⭐ 所以我们将这部分函数模块化

  1. 新建calculator.js,将 app.js 的函数剪贴到其中(此时再运行app.js会出错)

  2. 我们需要在 app.js 中引入我们新建的模块打印出来了一个 { } 空 Object 对象,⚠️ 这是因为 calculator.js 里的函数是不会自动暴露或者被输出的,我们需要明确告诉NodeJS哪一个函数需要被输出,那样才能被其他程序引入和调用

我的Vue之旅、02 ES6基础、模块、路径、IO

  1. 模块使用 module.exports 语句,在运行 app.js console输出函数 add

我的Vue之旅、02 ES6基础、模块、路径、IO

我的Vue之旅、02 ES6基础、模块、路径、IO

  1. 😅 那 subtract 怎么办呢,因为module.exports={ },我们可以往里添加新数据,我们只需要提供一对 key-value 即可

我的Vue之旅、02 ES6基础、模块、路径、IO

我的Vue之旅、02 ES6基础、模块、路径、IO

  1. console输出两个函数 add, subtract
// app.js const calculator = require('./calculator.js');  console.log(calculator);  let addResult = calculator.add(1,2);  console.log(`1 + 2 = ${addResult}`); 

我的Vue之旅、02 ES6基础、模块、路径、IO

const calculator = require('./calculator.js');  console.log(calculator);  let SubtractResult = calculator.subtract(5,2);  console.log(`5 - 2 = ${SubtractResult}`); 

我的Vue之旅、02 ES6基础、模块、路径、IO

function add(num1,num2){     return num1 + num2; }  function subtract(num1,num2){     return num1-num2; }  //module.exports.add = add; //module.exports.subtract = subtract;  //exports.add = add; //exports.subtract = subtract;  module.exports = {     add,  //add:add,     subtract     //subtract:subtract } 

💡 自定义模块小技巧

  • ⭐ 如果我们有很多模块,重复输入 module.exports 是很麻烦的,NodeJS给我们提供了一个便利,直接把最前面的 module 去掉
  • ⭐ 我们可以写成 module.exports = { 内容 } 的形式来简化,如果key-value相等,可以只写key
    我的Vue之旅、02 ES6基础、模块、路径、IO

🖥️ CMD终端的基本使用

sysdm.cpl  可快速打开计算机设置配置环境变量 md abc 	创建目录 abc rd abc 	删除目录 abc cd ..	进到上层目录   如果目录不是空的不能用rd删除目录,需要加两个参数 rd /s/q abc   (sub-directory quiet)  echo on a.txt 创建 a.txt 往里面覆盖内容 echo 123 > a.txt 往里面追加内容 echo 456 >> a.txt  cat a.txt 输出文件内容  rm a.txt 删除文件  cat > hello.txt 覆盖(按ctrl c 退出) cat >> hello.txt 追加内容(按ctrl c 退出)  在文件内按 Shift 右键 选择 在该目录下执行命令行 

Node.JS 全局成员

console.log(123);  // 包含文名称的全路径 console.log(__filename); // 文件的路径(不包含文件名称) console.log(__dirname);  // 定时函数 const a = setTimeout(()=>{     console.log(123); },3000);  setTimeout(()=>{console.log(123)},200); clearTimeout(a);  // process.argv 是一个数组,默认情况前两项数据分别是:Node.js的安装环境的路径,当前执行的js文件的全路径 // 从第三个参数开始表示命令行参数 console.log(process.argv); console.log(process.argv0);  // 打印当前系统的架构(x64, x86) console.log(process.arch); 

初识模块化(1-2)

/* 	index.js     模块化开发      传统非模块化开发有如下的缺点:     1、命名冲突(团队开发)     2、文件依赖(文件引入与先后次序)      前端标准的模块化规范:     1、AMD - requirejs     2、CMD - seajs      后端标准的模块化规范:     1、CommonJS - Node.js      模块化相关的规则:     1、 如何定义模块:一个js文件就是一个模块,模块内部的成员都是相互独立的     2、 模块成员的导出和引入 */  const a = function(a,b){     return parseInt(a) + parseInt(b); }  // 导出模块成员 //exports.sum = a;  module.exports = a; //此时这个模块本身就是个方法 
/* 	a.js     引入模块 */  const mod = require('./index.js');  console.log(mod);  //var ret = mod.sum(12,13);  var ret = mod(12,13);  console.log(ret); 

模块化细节补充

/* 	index.js     模块成员的导出 global      已经加载的模块会缓存,如果内存中有同样的文件就不会加载(性能优化) */  console.log('hello');  var flag = 123;  // 很少使用 global.flag = flag; 
/* 	a.js     模块文件的后缀3种情况: .js .json .node(C、C++)(不加后缀时加载顺序)     */  //require('./index.js');  //require('./index.js'); //require('./index.js');  require('./index');   // 后缀可以直接省略  var data = require('./data')  console.log(global.flag); console.log(data); 
// data.json {     "username":"张三",     "age":12 } 

ES6 let、const 使用规范

/*     声明变量 let和const */  // let 声明的变量不存在预解析 //console.log(flag); // var flag = 123; // let flag = 456;  // let 声明的变量不允许重复(同一作用域) //let flag = 123; //let flag = 456; //console.log(flag);  // ES6 引入了块级作用域 // 块内部let定义的变量,在外部访问不到 // if(true){ //     //var flag = 123; //     let flag = 123; // } /* -------------------------------------------------------------------------- */ {     // 这里是块级作用域     let flag = 123;     console.log(flag); } //console.log(flag); /* -------------------------------------------------------------------------- */ for(let i = 0; i < 3; i++){     // for循环括号中let声明的变量只能在循环体中使用     console.log(i); } /* -------------------------------------------------------------------------- */ // 在块级作用域内部,变量只能先声明再使用,因为没有预解析 if(true){     //console.log(flag);     let flag = 123; }  /* ---------------------------------- const --------------------------------- */  // const用来声明常量,不允许重新赋值,一开始必须要初始化 // 上述规则对 const 同样适用 // const n = 1; // n = 2;  

ES6 变量解构赋值

/*     变量的解构赋值 */  // var a = 1; // var b = 2; // var c = 3;  // var a = 1,b = 2,c = 3;  // * 数组的解构赋值,根据顺序,还可以添加默认值 //let [a,b,c] = [1,2,3];  //let [a=111,b,c] = [,123,];  //console.log(a,b,c);  // * 对象的解构赋值 //let {foo,bar} = {foo:'hello',bar : 'hi'}; //let {foo,bar} = {bar : 'hi',foo:'hello'};  // * 对象属性别名(如果起了别名,那么原来的名字就无效了) // let {foo:abc,bar} = {foo:'hello',bar : 'hi'}  // console.log(typeof(abc),bar,abc);  // * 对象的解构赋值设置默认值 let {foo:abc="hello",bar} = {bar : 'hi'}; console.log(abc,bar);  // * 把对象当中的属性与名称的进行绑定 let {cos,sin,random} = Math;  console.log(typeof cos,typeof sin,typeof random); /* -------------------------------------------------------------------------- */ // * 字符串的解构赋值  let [a,b,c,d,e,length] = "hello"; console.log(a,b,c,d,e,length);  let {length:len} = "hel";  console.log(len); 

ES6 字符串扩展与模板字符串

/*     字符串相关扩展     includes()  判断字符串中是否包含指定的子串(有的话返回true,否则返回false)                 参数一:匹配的子串;参数二:从第几个字符开始匹配     startsWith()  判断字符串是否以特定的子串开始     endsWith()  判断字符串是否以特定的子串结束      模板字符串 */  console.log('hello world'.includes('world',6));  let url = 'admin/index.php';  console.log(url.startsWith('admin')); console.log(url.endsWith('php'));  /* -------------------------------------------------------------------------- */ let obj = {     username : '李四',     age:'12',     gender: 'male' };  let tag = '<div><span>'+obj.username+'</span><span>'+obj.age+'</span><span>'+obj.gender+'</span></div>'; // 反引号表示模板,模板中的内容可以有格式,通过 ${}方式填充数据 let fn = (x)=> x; let tag2 = ` <div>     <span>${obj.username}</span>     <span>${obj.age}</span>     <span>${obj.gender}</span>     <span>${1+1}</span>     <span>${fn('nihao')}</span> </div> `  console.log(tag); console.log(tag2); // * 模板字符串后期维护方便 

ES6 函数扩展

/*     函数扩展     - 参数默认值     - 参数解构赋值     - rest参数     - ...扩展运算符 */  //参数默认值老式方法 function foo(param) {     let p = param || 'hello';     console.log(p); } foo();  function foo2(param = 'nihao') {     console.log(param); }  foo2(); foo2('123456');  /* -------------------------------------------------------------------------- */  function foo3(uname = 'list', age = 12) {     console.log(uname, age); }  foo3(); foo3('张三', 13);  // * 参数解构赋值 function foo4({     uname = 'lisi',     age = 10 } = {}) {     console.log(uname, age); }  foo4(); //! 不传参会出问题,可以给函数参数一个默认值 {} foo4({     uname: 'zhangsan',     age: 15 });  /* -------------------------------------------------------------------------- */ // * rest参数(剩余参数)... function foo5(a, ...params) {     console.log(params); }  foo5(1, 2, 3, 4, 5);  // 扩展运算符 ...  function foo6(a, b, c, d, e, f){     console.log(a + b + c + d + e + f); }  foo6(1,2,3,4,5,6); let arr = [1,2,3,4,5,6]; //foo6.apply(null,arr);   foo6(...arr);  // ! 扩展运算符  // 合并数组 let arr1 = [1,2,3]; let arr2 = [4,5,6]; let arr3 = [...arr1,...arr2]; console.log(arr3); 

apply、call函数妙用

ES6 箭头函数

我的Vue之旅、02 ES6基础、模块、路径、IO

node执行调试完成之后进程退出,这时候去看它的打印内容就看不到了  需要看到他具体的值,在打印的地方加上断点即可 
/*     箭头函数 */  function foo(){     console.log('hello'); } foo();  let foo2= () => console.log('hello'); foo2();  let foo3= x => x; foo3(123);  // * 多个参数必须用小括号包住 let foo4 = (a,b) => console.log(a+b); foo4(1,2);  let arr = [1,2,3]; arr.forEach(function(value,index){     console.log(value,index); });  arr.forEach((value,index)=>console.log(value,index));  // ! 箭头函数的注意事项 // - 箭头函数中的this取决于函数的定义位置而不是调用位置 // - 箭头函数不可以 new // - 箭头函数不可以使用 arguments 获取参数列表,可以使用rest参数代替 function foo5(){     // 使用call调用foo5时,这里的this其实就是call的第一个参数     console.log(this);     setTimeout(()=>{         console.log(this,this.num);     },1000); }  foo5(); foo5.call({num:1}); /* -------------------------------------------------------------------------- */ let foo6 = ()=> {this.num = 123;} //new foo6(); /* -------------------------------------------------------------------------- */ let foo7 = (a,b) =>{     console.log(a,b,arguments); //这种方式获取不到实参列表 } foo7(123,456);  let foo8 = (...param) => {  //rest参数     console.log(param); } foo8(123,456); 

ES6 类与继承

/*     类与继承 */ // function Animal(name){ //     this.name = name; // }  // Animal.prototype.showName = function(){ //     console.log(this.name); // } // var a = new Animal('Tom'); // a.showName(); // var b = new Animal('Jerry'); // a.showName(); /* -------------------------------------------------------------------------- */  class Animal{     // * 静态方法(静态方法只能通过类名调用,不可以使用实例对象调用)     static showInfo(){         console.log('hello');     }     // * 构造函数     constructor(name){         this.name = name;     }     showName(){         console.log(this.name);     } } let a = new Animal('spike'); a.showName(); Animal.showInfo(); /* -------------------------------------------------------------------------- */ // 类的继承 extends class Dog extends Animal{     constructor(name,color){         super(name); // super用来调用父类         this.color = color;     }     ShowColor(){         console.log(this.color);     } }  let d = new Dog('doudou','yellow'); d.showName(); d.ShowColor(); Dog.showInfo();  

Buffer基本操作

console.log(Buffer.isEncoding('utf8')); console.log(Buffer.isEncoding('gbk'));  let buf = Buffer.from('hello'); console.log(buf); console.log(Buffer.isBuffer(buf)); console.log(Buffer.isBuffer({}));  let buf2 = Buffer.from('中国','ascii'); console.log(Buffer.byteLength(buf2)); console.log(buf2.toString());  let buf31 = Buffer.alloc(3); let buf32 = Buffer.alloc(5); let buf33 = Buffer.concat([buf31,buf32]); console.log(Buffer.byteLength(buf33));  /* -------------------------------------------------------------------------- */ // 实例方法   let buf4 = Buffer.alloc(5); buf4.write('hello',2,2); // * 向buffer对象中写入内容  [from] - counts console.log(buf4);  let buf51 = Buffer.from('hello'); let buf52 = buf51.slice(); console.log(buf51==buf52); // ! 两个不同的buffer对象 buf52 = buf51.slice(1,3); // * 截取buffer对象的内容 [from] - (to) console.log(buf52.toString());  // ! toJSON方法不需要显式调用,当JSON.stringify方法调用的时候会自动调用toJSON方法  const buf6 = Buffer.from('hello'); const json = JSON.stringify(buf6); // * 将buffer对象转成JSON,对应的十进制 console.log(json); 

Node.JS 路径操作

/*     路径操作 */ const path = require('path');  // * 获取路径的最后一部分 console.log(path.basename('/foo/bar/baz/asdf/quux.html')); console.log(path.basename('/foo/bar/baz/asdf/quux.html','.html'));  // * 获取路径 console.log(__dirname); console.log(path.dirname('/abc/qq/www/aabc.txt'));  // * 获取文件扩展名 console.log(path.extname('index.html'));  // * 路径的格式化处理 // path.format() obj->string // path.parse() string->obj  let obj = path.parse(__filename); console.log(obj);  /* {   root: 'F:\',   文件根路径   dir: 'F:\Node.JS\Codes\1031\NodeJS基础\2-1 路径操作', 文件全路径   base: 'index.js', 文件名称   ext: '.js',   文件扩展名   name: 'index' 文件名称 } */  let objpath = {     root: 'd:\',       base: 'abc.txt',     dir : 'd:\aaaaa\cccc\',      ext: '.txt',        name: 'abc',  }; let strPath = path.format(objpath); console.log(strPath);  // * 判断是否为绝对路径 path.isAbsolute('C:/foo/..');   // * 拼接路径,在连接路径的时候会格式化 console.log(path.join('/foo','bar','baz/asdf','quux','../../')); // ! 两个点是上层路径,一个点表示当前路径  // * 规范化路径 console.log(path.normalize('/foo/bar//baz/asdf/quux/..')) console.log(path.normalize('C:\temp\\foo\bar\..\'));  // * 从两个绝对路径换算出来相对路径 console.log(path.relative('C:\orandea\test\aaa', 'C:\orandea\impl\bbb'));  // * 解析路径 console.log(path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif'));  // * 两个特殊属性 console.log(path.delimiter); // * 环境变量分隔符 windows 是 ; linux 是 : console.log(path.sep);  // * 路径分隔符,windows 是   LINUX是 / 

异步I/O

我的Vue之旅、02 ES6基础、模块、路径、IO

/*     异步I/O input/output     - 文件操作     - 网络操作      在浏览器中也存在异步操作:     - 定时任务     - 事件处理     - Ajax回调处理      js的运行是单线程的     引入了事件队列机制      Node.js中的事件模型与浏览器中的事件模型类似     单线程+事件队列      Node.js中异步执行的任务:     1、文件I/O     2、网络I/O      基于回调函数的编码风格 */ 

文件操作

文件状态

/*     文件状态 */ const fs = require('fs'); console.log(1); fs.stat(`${__dirname}/data.txt`,(err,stat)=>{     // ! 一般回调函数的第一个参数是错误对象,如果err为null,表示没有错误,否则表示报错了     if(err) return;     console.log(stat);     if(stat.isFile()){         console.log('文件');     }     else if(stat.isDirectory()){         console.log('目录');     }     /*      atime 访问时间     mtime 文件数据发生变化的时间     ctime 文件状态信息发生变换的时间(比如文件的权限)     birthtime 文件创建的时间     */ }); console.log(2);  // 同步操作 // console.log(1); // let ret = fs.statSync(`${__dirname}/data.txt`); // console.log(ret); // console.log(2);  // ! 当主线程执行完了才会空闲,去把事件队列中的任务取出来 

读文件

/*     读文件操作 */ const fs = require('fs'); const path = require('path');  let strPath = path.join(__dirname,'data.txt');  fs.readFile(strPath,(err,data)=>{     if(err) return;     console.log(data); // * 打印出字节数组     console.log(data.toString()); });  // * 第二个参数可以指定编码,得到的数据是字符串 // * 如果没有第二个参数,那么得到的就是Buffer实例对象 fs.readFile(strPath,'utf8',(err,data)=>{     if(err) return;     console.log(data); // * 打印出字符串 });  // ! 同步操作,不需要回调函数 let ret = fs.readFileSync(strPath,'utf8'); console.log(ret); 

写文件

/*     写文件操作 */ const fs = require('fs'); const path = require('path');  let strpath = path.join(__dirname,'data.txt'); // * 默认编码方式 encoding : utf 8 // fs.writeFile(strpath,'hello cat',(err)=>{ //     if(err) throw err; //     else { //         console.log('文件写入成功'); //     } // }) // ! 多次写入需要使用数据流的方式  // let buf = Buffer.from('world'); // fs.writeFile(strpath,buf,(err)=>{ //     if(err) throw err; //     else { //         console.log('文件写入成功'); //     } // })  // ! 同步操作 fs.writeFileSync(strpath,'tom and jerry'); 

文件流式操作(针对大文件)

/*     大文件操作(流式操作)     fs.createWriteStream(path[, options])     fs.createReadStream(path[, options]) */ const path = require('path'); const fs = require('fs');  let sPath = path.join(__dirname,'../files','file.zip'); let dPath = path.join('P:\','file.zip');  let readStream = fs.createReadStream(sPath); let writeStream = fs.createWriteStream(dPath);  // 基于事件的处理方式 // * 举例 // $('input[type=button]').on('click',function(){ //     console.log('hello'); // });  // * 在NodeJS中无DOM操作,所以没有点击事件  // let num = 0; // readStream.on('data',(chunk)=>{ // ! data 是固定的事件,每读取一部分就触发 //     num++; //     writeStream.write(chunk); // });  // readStream.on('end',()=>{ // ! end 是固定的事件 //     console.log(num); //     console.log('文件处理完成'); // })  /* -------------------------------------------------------------------------- */  // * 另外一种方式,pipe的作用直接把输入流(从磁盘加载到内存)与输出流(从内存写入到磁盘) readStream.pipe(writeStream);  /* -------------------------------------------------------------------------- */  fs.createReadStream(sPath).pipe(fs.createWriteStream(dPath)); 

目录操作

/*     目录操作     - 创建目录     fs.mkdir(path[, options], callback)     fs.mkdirSync(path[, options])     - 读取目录     fs.readdir     fs.readdirSync  */  const path = require('path'); const fs = require('fs');  // fs.mkdir(path.join(__dirname,'../files','abc'),(err)=>{ //     console.log(err); // });  // fs.mkdirSync(path.join(__dirname,'../files','abc')); /* -------------------------------------------------------------------------- */ // 读取目录下的目录与文件 // fs.readdir(path.join(__dirname,'..'),(err,files)=>{ // console.log(err,files); //     files.forEach((item,index)=>{ //         fs.stat(path.join(__dirname,'..',item),(err,stat)=>{ //             if(stat.isFile()){ //                 console.log(item,'文件'); //             } //             else if(stat.isDirectory()){ //                 console.log(item,'目录'); //             } //         }) //     }) // });  // ! 同步操作 // let files = fs.readdirSync(path.join(__dirname,'..')); // files.forEach((item,index)=>{ //     fs.stat(path.join(__dirname,'..',item),(err,stat)=>{ //         if(stat.isFile()){ //             console.log(item,'文件'); //         } //         else if(stat.isDirectory()){ //             console.log(item,'目录'); //         } //     }) // })  // ! 删除目录 fs.rmdir(path.join(__dirname,'../files','abc'),(err)=>{     console.log(err); });  fs.rmdirSync(path.join(__dirname,'../files','abc')); 

文件实操案例(初始化目录与文件)

/*     文件操作案例(初始化目录结构) */  const path = require('path'); const fs = require('fs');  let root = 'P:\' let fileContent = ` <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <meta http-equiv="X-UA-Compatible" content="IE=edge">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <title>Document</title> </head> <body>     欢迎访问 </body> </html> `;  // 初始化数据 let initData = {     projectName : 'mydemo',     data : [{         name : 'img',         type : 'dir'     },{         name : 'js',         type : 'dir'     },{         name : 'css',         type : 'dir'     },{         name : 'index.html',         type : 'file'     }] };  // 创建项目根路径 fs.mkdir(path.join(root,initData.projectName),(err)=>{     if(err) return;     // 创建子目录和文件     initData.data.forEach((item)=>{         if(item.type == 'dir'){             // * 创建子目录             fs.mkdirSync(path.join(root,initData.projectName,item.name));         }         else if(item.type == 'file'){             fs.writeFileSync(path.join(root,initData.projectName,item.name),fileContent);         }     }) });