# 笔记
# 2022 年 3 月 1 日
# ES6 Module 动态加载
ES6 模块是编译时加载,CommonJS 和 AMD 则是运行时加载。
ES2020 提案引入了 import() 函数,支持动态加载模块,并且 import() 返回的是一个 Promise 对象
const main = document.querySelector("main")
import(`./section-modules/${someVariable}.js`)
.then(module => {
module.loadPageInto(main)
})
.catch(err => {
main.textContent = err.message
})
import()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行import()函数与所加载的模块没有静态连接关系,这点也是与import语句不相同import()类似于Node的require方法,区别主要是前者是异步加载,后者是同步加载
import() 加载模块成功以后,这个模块会作为一个对象,当作 then 方法的参数。因此,可以使用对象解构赋值的语法,获取输出接口。
import("./myModule.js").then(({ export1, export2 }) => {
// ...·
})
// 如果模块有 default 输出接口,可以用参数直接获得
import("./myModule.js").then(myModule => {
console.log(myModule.default)
})
// 在 async 函数之中
async function main() {
const myModule = await import("./myModule.js")
const { export1, export2 } = await import("./myModule.js")
const [module1, module2, module3] = await Promise.all([
import("./module1.js"),
import("./module2.js"),
import("./module3.js")
])
}
main()
# 2022 年 3 月 2 日
# ES6 模块与 CommonJS 模块的差异
CommonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用CommonJS模块是运行时加载,ES6模块是编译时输出接口CommonJS模块的require()是同步加载模块,ES6模块的import命令是异步加载,有一个独立的模块依赖的解析阶段
JavaScript 现在有两种模块。一种是 ES6 模块,简称 ESM;另一种是 CommonJS 模块,简称 CJS
CommonJS 模块是 Node.js 专用的,与 ES6 模块不兼容。语法上面,两者最明显的差异是:CommonJS 模块使用 require() 和 module.exports,ES6 模块使用 import 和 export
从 Node.js v13.2 版本开始,Node.js 已经默认打开了 ES6 模块支持。Node.js 要求 ES6 模块采用 .mjs 后缀文件名。也就是说,只要脚本文件里面使用 import 或者 export 命令,那么就必须采用 .mjs 后缀名。Node.js 遇到 .mjs 文件,就认为它是 ES6 模块。如果不希望将后缀名改成 .mjs,可以在项目的 package.json 文件中,指定 type 字段为 module。一旦设置了以后,该项目的 JS 脚本,就被解释成 ES6 模块。
{
"type": "module"
}
如果这时还要使用 CommonJS 模块,那么需要将 CommonJS 脚本的后缀名都改成 .cjs。如果没有 type 字段,或者 type 字段为 commonjs,则 · 脚本会被解释成 CommonJS 模块。
总结为一句话:.mjs 文件总是以 ES6 模块加载,.cjs 文件总是以 CommonJS 模块加载,.js 文件的加载取决于 · 里面 type 字段的设置。
CommonJS模块加载ES6模块
CommonJS 的 require() 命令不能加载 ES6 模块,会报错,只能使用 import() 这个方法加载。
;(async () => {
await import("./my-app.mjs")
})()
ES6模块加载CommonJS模块
ES6 模块的 import 命令可以加载 CommonJS 模块,但是只能整体加载,不能只加载单一的输出项。
// 正确
import packageMain from "commonjs-package"
// 报错
import { method } from "commonjs-package"
# 2022 年 3 月 3 日
# 类型断言
TypeScript 允许你覆盖它的推断,并且能以你任何你想要的方式分析它,这种机制被称为「类型断言」。
TypeScript 类型断言用来告诉编译器你比它更了解这个类型,并且它不应该再发出错误。
// 初版类型断言语法如下,
let foo: any;
let bar = <string>foo; // 现在 bar 的类型是 'string'
// 因上述语法与JSX语法存在歧义
// 因此建议使用以下语法来为类型断言
let bar as foo;
双重断言?
# 2022 年 3 月 4 日
# 类型别名
TypeScript 提供了为类型注解设置别名的便捷语法,你可以使用 type SomeName = someValidTypeAnnotation 来创建别名
// StrOrNum 就是类型别名,后面的这一串 string | number 是类型注解
type StrOrNum = string | number
// 使用
let sample: StrOrNum
sample = 123
sample = "123"
// 会检查类型
sample = true // Error
# 2022 年 3 月 5 日
# TS 命名空间
命名空间可以作为组织代码的一种手段,帮助我们记录类型并且不用担心与其他对象产生命名冲突
可以将命名空间 export 出去,然后再通过命名空间访问暴露出来的变量。
namespace Utility {
// 这里注意,命名空间里面的变量也需要export,否则在外面访问不了
export function log(msg) {
console.log(msg);
}
export function error(msg) {
console.log(msg);
}
}
// usage
Utility.log('Call me');
Utility.error('maybe');
# 2022 年 3 月 6 日
# @types
可以通过 npm 来安装使用 @types,如下为 jQuery
npm install @types/jquery --save-dev
默认情况下,TypeScript 会自动包含支持全局使用的任何声明定义。例如 jquery,应该能够在项目中开始全局使用 $
此外,还可以通过 tsconfig.js 的 compilerOptions.types 选项,引入指定的类型。如下所示,通过配置 compilerOptions.types: [ "jquery" ] 后,只允许使用 jquery 的 @types 包,即使安装了另一个声明文件,比如 npm install @types/node,它的全局变量(例如 process)也不会泄漏到你的代码中,直到你将它们添加到 tsconfig.json 类型选项。
{
"compilerOptions": {
"types": ["jquery"]
}
}
TS 类型声明包搜索地址:https://www.typescriptlang.org/dt/search?search= (opens new window)
# 2022 年 3 月 7 日
# @types、types、typeRoots
tsconfig.js 中的:types、typeRoots 都是用于指定加载包的配置项
types是引入指定的包,并且只有列出来的才会被引入typeRoots是指定一个路径,并且该路径下的所有包都会被引入@types默认所有可见的@types包会在编译过程中被包含进来
(可以考虑将项目的 .d.ts 等类型声明文件统一放置在 src/@types/下,然后在 typeRoots 中指定)
参考地址:https://www.tslang.cn/docs/handbook/tsconfig-json.html (opens new window)
# 2022 年 3 月 8 日
# shims-vue.d.ts 文件作用
.vue 类型文件本身不被 ts 识别,ts 只能识别 .ts、.d.ts、.tsx 后缀文件
加上模块声明是为了能够被 webpack 处理,并且能够识别 export 出来的对象
declare module '*.vue' { // Ambient module declarations 环境模块说明
import Vue from 'vue'
export default Vue
}
参考地址:https://fettblog.eu/typescript-modules-for-webpack/ (opens new window)
# 2022 年 3 月 9 日
# .d.ts 文件
- 会全局自动生效,需要注意命名冲突问题,结合
namespace使用 - 如果依赖某个全局库,可以使用
/// <reference types="..." />命令 (em...没有实际使用过)
参考文档:preventing-name-conflicts (opens new window)
# 2022 年 3 月 10 日
# 常用方法类型
setTimeout、setInterval的类型为number(如果仍然异常,可以考虑使用window.setTimeout)element-ui中的各种类型组件都有其对应的类型,如:el-form对应Form;el-table对应Table
# 2022 年 3 月 11 日
# 类型守卫
类型守卫主要指一些在特定作用域内 收缩 变量类型的类型判断行为(也就是类型保护?)
typeof类型判断instanceof原型判断in属性判断==、===等判断运算符
function test(arg: string | number) {
if (typeof arg == "string") {
// 这里 arg 的类型 收紧 为 string
} else {
// 这里 arg 的类型 收紧 为 number
}
}
# 2022 年 3 月 12 日
# TS 运算符
- 非空断言运算符
!::表达式之后写!:实际上是一个类型断言,该值不是null和undefined
# 2022 年 3 月 13 日
# pnpm 一探
pnpm 类似于 npm,可以将多个项目相同的依赖存储在一个统一的位置,当安装软件包时, 其包含的所有文件都会硬链接自此位置,而不会占用 额外的硬盘空间,可以极大程度的减轻存储压力以及增加安装速度
文档地址:https://www.pnpm.cn/motivation (opens new window)
实际体验发现:
- 安装单个依赖时,应该是扫了一遍
node_modules,然后再下载依赖,话费的时间比直接npm install要长 - 旧项目改用
pnpm时,发现webpack、url-loader等依赖都会出现问题,如10KB以下的图片压缩异常 - 尝试两个项目用
pnpm安装,但发现整理的包体积并没有缩小
# 2022 年 3 月 14 日
# NodeJS is not undef
在 tsconfig.json 中的 types 选项中,添加了 node 后,使用 NodeJS 命名空间提示 NodeJS is not undef,可以在 eslintrc.js 中增加
{
"globals": {
"NodeJS": true
}
}
# 2022 年 3 月 15 日
# XSS
XSS 攻击有两大要素: 1. 攻击者提交恶意代码。 2. 浏览器执行恶意代码。
在使用 .innerHTML、.outerHTML、document.write() 时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent、.setAttribute() 等。
- script 标签
- img 标签
- 字符转义
- meta 标签中的 url:
<META HTTP-EQUIV=”refresh” CONTENT=”0; URL=http://;URL=javascript:alert(‘XSS’);”>