path.join() && path.resolve() && url.resolve()
path.join()和 path.resolve()的区别
现在写代码的时候有时候使用 path.join(**dirname,‘dist’)有时候用 path.resolve(**dirname,‘dist’),都是能拼接出来一个绝对路径,但是具体有什么区别呢? ### path.join()方法是将多个参数字符串合并成一个路径字符串
console.log(path.join(__dirname,'a','b')); 假如当前文件的路径是E:/node/1,那么拼接出来就是E:/node/1/a/b。
console.log(path.join(__dirname,'/a','/b','..')); 路径开头的/不会影响拼接,..代表上一级文件,拼接出来的结果是:E:/node/1/a
console.log(path.join(__dirname,'a',{},'b')); 而且path.join()还会帮我们做路径字符串的校验,当字符串不合法时,会抛出错误:Path must be a string.
path.resolve()方法是以程序为根目录,作为起点,根据参数解析出一个绝对路径
* 以应用程序为根目录
* 普通字符串代表子目录
* /代表绝对路径根目录
> console.log(path.resolve()); 得到应用程序启动文件的目录(得到当前执行文件绝对路径) E:\zf\webpack\1\src
> console.log(path.resolve(‘a’,’/c’)); E:/c ,因为/斜杠代表根目录,所以得到的就是 E:/c
所以我们一般拼接的时候需要小心点使用/斜杠
console.log(path.resolve(__dirname,‘img/so’)); E:\zf\webpack\1\src\img\so 这个就是将文件路径拼接,并不管这个路径是否真实存在。
console.log(path.resolve(‘wwwroot’, ‘static_files/png/’, ‘…/gif/image.gif’)) E:\zf\webpack\1\src\wwwroot\static_files\gif\image.gif
这个是用当前应用程序启动文件绝对路径与后面的所有字符串拼接,因为最开始的字符串不是以/开头的。
…也是代表上一级目录。
path.resolve() 案例
var path = require("path"); //引入node的path模块
path.resolve("/foo/bar", "./baz"); // returns '/foo/bar/baz'
path.resolve("/foo/bar", "baz"); // returns '/foo/bar/baz'
path.resolve("/foo/bar", "/baz"); // returns '/baz'
path.resolve("/foo/bar", "../baz"); // returns '/foo/baz'
path.resolve("home", "/foo/bar", "../baz"); // returns '/foo/baz'
path.resolve("home", "./foo/bar", "../baz"); // returns '/home/foo/baz'
path.resolve("home", "foo/bar", "../baz"); // returns '/home/foo/baz'
url.resolve()
const url = require("url");
url.resolve("/one/two/three", "four"); // 'one/two/three/four'
url.resolve("/one/two/three", "/four"); // 'one/two/four'
url.resolve("/one/two/", "four"); // 'one/two/four'
几个常用的 ejs 语法
1.转义输出
<%= 变量名 %>
//这个是转义输出,可以把变量名替换成自己需要的东西.
// js文件
ejs.renderFile("./views/test.ejs", { name: "wzz" }, function(err, data) {
if (err) {
console.log(err);
} else {
console.log(data);
}
});
<!-- ejs文件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<%=name%>
</body>
</html>
最后我们可以发现 name 变量,在控制台被替换成了 wzz.
2.不转义输出
<%- 变量名%>
不转义输出可以把定义的字符串不转义的输出.
我们可以这么用,这边我们省略了第二个不使用的 json 数据
<!-- ejs文件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<% var str='<div><div>'; %>
<%-str %>
<%=str %>
</body>
</html>
输出结果如下
<div><div>
<div><div>
3.js 代码
//这里面可以写javascript的代码.我们可以这么使用
<% Javascript代码 %>
案例
<!-- ejs文件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<%for(var i=0;i<json.arr.length;i++){%>
<div>user:<%=json.arr[i].user%> pass:<%=json.arr[i].pass%><div>
<%}%>
</body>
</html>
4.使用 include 引入外部的文件
<% include 文件的地址 %>
案例
<!-- ejs文件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<% include ../content.txt %>
</body>
</html>
模块化规范
在 ES6 之前 js 没有提供模块化的相关功能 , 社区给出了相关的解决方案
AMD Asynchronous Module Definition 异步模块定义
提供异步加载模块的机制
异步加载提前执行,出现错误可以提前发现,但容易产生资源浪费
代表作:require.js
$ sudo cnpm install requirejs -S
- 模块导出 define([依赖注入],(¥)=>{ return { 自定义模块内容 } })
- 模块的导入 require.config({}) 进行配置, 通过 require([依赖注入],($$)=> { 独立作用域 })
///定义模块
//第一个参数 依赖列表
define(["jquery"], function() {
return {
sayHi: function() {
console.log("hi");
},
max: function() {
return Math.max.apply(null, arguments);
}
};
});
// 配置require
require.config({
// baseUrl: "../../node_modules",
paths: {
// 文件列表
// 属性是 模块名
// 属性值 模块路径 不写文件后缀名
jquery: "../node_modules/jquery/dist/jquery.min",
index: "./index"
}
});
require(["jquery"], function($$) {
$$("#btn").on("click", function() {
$$("div").hide(2000);
});
});
require(["jquery"], function($) {
console.log($);
console.log(123);
});
require(["index"], function(obj) {
console.log(obj.max(63, 173, 73, 77, 185, 12));
console.log($);
});
// require(['index', 'jquery'], function(obj) {
// console.log(obj.max(63, 173, 73, 77, 185, 12));
// console.log($);
// })
CMD Common Module Definition 同步模块定义
模块按需加载
将延迟加载,需要时动态加载,可以减少资源浪费,但等待时间长,出错 时间延后,
代表作:sea.js
$ sudo cnpm i seajs -S
经常使用的 API 只有 define, require, require.async, exports,module.exports 这五个
define(function(require, exports) {
// 获取模块 a 的接口
var a = require("./a");
// 调用模块 a 的方法
a.doSomething();
require.async(["./c", "./d"], function(c, d) {
c.doSomething();
d.doSomething();
});
console.log(require.resolve("./b"));
// ==> http://example.com/path/to/b.js
// 对外提供 foo 属性
exports.foo = "bar";
// 对外提供 doSomething 方法
exports.doSomething = function() {};
module.exports = {
foo: "bar",
doSomething: function() {}
};
});
Common.js 后台模块化规范
代表作 node.js
- 导出 module.exports = XXX
- 模块导入 const XXX = require(‘相对路径’)
var express = require("express");
var router = express.Router();
/* GET home page. */
router.get("/", function(req, res, next) {
// res.render 渲染一个模板
// render的第一个函数 指的是模板文件的名字
// 第二个参数 是传给模板的数据 对象
// 路由在渲染页面时,将数据传递给模板引擎
res.render("index", {
title: "Express",
username: "小明"
});
});
module.exports = router; //定位
// 引入路由
var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
ES6 的 module 模块化解决方案
服务器运行
ES6 模块不是对象 , 而是通过 export 命令来指定输出代码, 再 通过import 命令输入
每一个模块内声明的变量都是局部变量, 不会污染全局作用域;
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
// CommonJS模块
let { stat, exists, readFile } = require('fs');
// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
上面代码的实质是整体加载fs模块(即加载fs的所有方法),生成一个对象(_fs),然后再从这个对象上面读取 3 个方法。这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。
ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
// ES6模块
import { stat, exists, readFile } from 'fs';
上面代码的实质是从fs模块加载 3 个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。
ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";。
严格模式主要有以下限制。
* 变量必须声明后再使用
* 函数的参数不能有同名属性,否则报错
* 不能使用with语句
* 不能对只读属性赋值,否则报错
* 不能使用前缀 0 表示八进制数,否则报错
* 不能删除不可删除的属性,否则报错
* 不能删除变量delete prop,会报错,只能删除属性delete global[prop]
* eval不会在它的外层作用域引入变量
* eval和arguments不能被重新赋值
* arguments不会自动反映函数参数的变化
* 不能使用arguments.callee
* 不能使用arguments.caller
* 禁止this指向全局对象
* 不能使用fn.caller和fn.arguments获取函数调用的堆栈
* 增加了保留字(比如protected、static和interface)
其中,尤其需要注意this的限制。ES6 模块之中,顶层的this指向undefined,即不应该在顶层代码使用this。
案例
// export class Student {
// constructor(name) {
// this.name = name;
// }
// }
// export var a = 10;
// export function fn(){
// console.log('ok');
// }
export { Student, a, fn };
class Student {
constructor(name) {
this.name = name;
}
}
var a = 10;
function fn() {
console.log("ok");
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script>
import { Student } from "./DemoClass.js";
var s = new Student("zhangsan");
console.log(s);
import { a } from "./DemoClass.js";
console.log(a);
import { fn } from "./DemoClass.js";
fn();
</script>
<script type="module">
import { Student as s, a, fn } from "./DemoClass.js";
var s1 = new s("zhangsan");
console.log(s1);
console.log(a);
fn();
</script>
</head>
<body></body>
</html>