TS
TypeScript 包含了 JavaScript 的所有内容,是 他的的超集。
TS编译
浏览器不能直接运⾏ TypeScript 代码,需要编译为 JavaScript 再交由浏览器解析器执⾏。
命令行编译
第⼀步:创建⼀个 demo.ts ⽂件
const person = {
name:'李四',
age:18
}
console.log(`我叫${person.name},我今年${person.age}岁了`)第二步:全局安装 TypeScript
npm i typescript -g第三步:使⽤命令编译 .ts ⽂件
tsc demo.ts自动化编译
第⼀步:创建 TypeScript 编译控制文件
会生成⼀个 tsconfig.json 配置文件,默认编译的 JS 版本是 ES7 ,可以手动调整。
tsc --init第二步:监视目录中的 .ts 文件变化
tsc --watch 或tsc -w
//当编译出错时不⽣成.js ⽂件
tsc --noEmitOnError --watch基本语法
==与===
==:比较时会进行类型转换,如果转换后值相等,则返回
true。ts1 == '1' // true,因为字符串 '1' 被转换成数字 1 0 == false // true,因为 false 被转换成数字 0 null == undefined // true,因为它们被认为是相等的===:比较时不进行类型转换,只有类型和值都相同时才返回
true。ts1 === '1' // false,因为一个是数字,一个是字符串 0 === false // false,因为一个是数字,一个是布尔值 null === undefined // false,因为它们是不同的类型
声明关键字
var
作用域:函数作用域或全局作用域
在函数内声明变量,则整个函数内任意位置均可访问
在函数外声明变量,那么全局可访问。
变量提升:
var声明的变量会被提升到函数或全局作用域的顶部,但不会初始化(undefined)。重复声明:能在同一作用域内多次声明同一个变量
let、const
- 作用域:块作用域(即在花括号
{}内有效)。 - 变量提升:let、const声明的变量也会被提升,但在声明之前不能访问(暂时性死区)。
- 重复声明:let、const不能在同一作用域内多次声明同一个变量,且const声明时必须初始化,且不能重新赋值。
// 一、作用域限制
{
var a = 1;
let b = 2;
const c = 5;
}
// 可以访问a
console.log(a);
// 不可以访问b和c
console.log(b);
console.log(c);
// 二、重复声明
// var 可以声明多次
var m = 1
var m = 2
// let 只能声明一次,Identifier 'n' has already been declared
let n = 3
let n = 4
// 三、变量提示
// var 会变量提升,let 不存在变量提升
console.log(x); // undefined
var x = 10;
console.log(y); //ReferenceError: y is not defined
let y = 20;
// 四、const不可变性
// 声明之后不允许改变,且声明时必须初始化,否则会报错
const a = 1;
a = 3; //Uncaught TypeError: Assignment to constant variable.JavaScript 类型
string、number、boolean、null、undefined、bigint、symbol、object(包含: Array 、 Function 、 Date 、 Error 等...... )
- 原始类型:如 number 、 string ,它们在内存中占⽤空间少,处理速度快。
- 包装对象:如 Number 对象、 String 对象,是复杂类型,在内存中占⽤更多空间。
let str1: string
str1 = 'hello'
//报错,不能将包装对象赋值给原始类型
str1 = new String('hello')
//⾃动装箱:JavaScript 在必要时会⾃动将原始类型包装成对象,以便调⽤⽅法或访问属性
// 原始类型字符串
let str = 'hello';
// 当访问str.length时,JavaScript引擎做了以下⼯作:
let size = (function() {
// 1. ⾃动装箱:创建⼀个临时的String对象包装原始字符串
let tempStringObject = new String(str);
// 2. 访问String对象的length属性
let lengthValue = tempStringObject.length;
// 3. 销毁临时对象,返回⻓度值
// (JavaScript引擎⾃动处理对象销毁,开发者⽆感知)
return lengthValue;
})();string
let s = 'Hello world!';
s.indexOf('o')// 返回字符串出现下标
// 三个方法都支持第二个参数,表示开始搜索的位置
s.startsWith('Hello') // 返回布尔值,是否以什么开头
s.endsWith('!') // 返回布尔值,是否以什么结尾
s.includes('o') // 返回布尔值,是否包含字符串
s.repeat(n) // 返回s重复n次的字符串
s.trim()// 消除头尾空格
s.trimStart()// 消除字符串头部的空格
s.trimEnd()// 消除尾部的空格
// 字符串补全长度的功能:如果某个字符串不够指定长度,会在头部或尾部补全。
s.padStart(n, str)
s.padEnd(n, str)Object
object
可以存储所有非原始类型,如对象、函数、数组等,不包括基本数据类型和null、undefined。
let a:object //a的值可以是任何【⾮原始类型】,包括:对象、函数、数组等
// 不能为基本数据类型
a=1
// 不能为null或undefined
a = null
a = undefinedObject
除了 undefined 和 null 的任何值 ,包括基本数据类型
let b:Object
// 可以为基本数据类型,会调用Object封装
b = 1
b = true
b = '你好'
// 以下代码均有警告
b = null
b = undefined使用
// 返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的属性值,Symbol属性会被忽略
const obj = { foo: 'd', 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj) // ["b", "c", "a", "d"]
// 返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值对数组,Symbol属性会被忽略
let obj = {
[Symbol()]: 123,
foo: 'abc',
1: 'a',
2: 'b'
}
Object.entries(obj);// [ ['1', 'a'], ['2', 'b'], [ 'foo', 'abc' ] ]
// Object.entries()的逆操作,用于将一个键值对数组转为对象
Object.fromEntries([
[Symbol(), 'm'],
['1', 'a'],
['2', 'b'],
['foo', 'abc']
])
// {1: 'a', 2: 'b', foo: 'abc', Symbol(): 'm'}Set
size:返回 Set 结构的成员总数
add(val):添加某个值,返回 Set 结构本身
delete(val):删除某个值,返回一个布尔值,表示删除是否成功
has(val):返回一个布尔值,表示该值是否为
Set的成员clear():清除所有成员,没有返回值
forEach((val, key, set) => {}):使用回调函数遍历每个成员,val和key相同,set是集合本身
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
// set创建,可以传入多个参数
let s1 = new Set([4, 5, 6]);
// 遍历
//for (let item of set.keys())
//for (let item of set.values())
for (let item of set.values()){
console.log(item);
// red
// green
// blue
}
for (let item of set.entries()) {
console.log(item);
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]
}
// 数组去重
let arr = [1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7];
arr = [...new Set(arr)]; // [1,2,3,4,5,6,7]
// 实现交、并、差
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 交集
let intersect = new Set([...a].filter(item => b.has(item)))
// 并集
let union = new Set([...a, ...b]);
// (a 相对于 b 的)差集
let difference = new Set([...a].filter(item => !b.has(item)))WeakSet
WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别
WeakSet 的成员只能是对象,不能是其他类型的值
WeakSet 中的对象(非值类型)都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用, 可以用于储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏
add(val):添加某个值,返回 Set 结构本身
delete(val):删除某个值,返回一个布尔值,表示删除是否成功
has(val):返回一个布尔值,表示该值是否为Set的成员
Map
- size:返回 Map 结构的成员总数
- set(key,value):该方法设置键名key对应的键值为value,然后返回整个 Map 结构(可连续调用)。如果key已经有值,则键值会被更新,否则就新生成该键
- get(key):该方法读取key对应的键值,如果找不到key,返回undefined
- has(key):该方法返回一个布尔值,表示某个键是否在当前 Map 对象之中
- delete(key):该方法删除某个键,返回true。如果删除失败,返回false
- clear():该方法清除所有成员,没有返回值
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回所有成员的遍历器
- forEach():遍历 Map 的所有成员
// 创建多个变量的map
let map = new Map([
[1, 55],
['good', 123],
[{}, 555]
])
// 链式调用存入变量
myMap.set(obj, { age: 18 }).set(sym, 456);
// Map 转 数组
let arr = [...map]; // [[1, 55], ['good, 123], [{}, 555]]
// 对象转为Map,可以通过Object.entries()
let obj = { a: 1, b: 2 };
let map = new Map(Object.entries(obj));WeakMap
WeakMap结构与Map结构类似,也是用于生成键值对的集合。它与Map有两个区别
WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名
WeakMap 中的对象(非值类型)都是弱引用,即垃圾回收机制不考虑 WeakMap 对该对象的引用。用于储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏
myweakMap.set(key, val):添加键值对,返回 Map 结构本身
myweakMap.has(key):返回一个布尔值,表示该值是否为 Map的成员
myweakMap.get(key):返回 key 对应的值
myweakMap.delete(key):删除 key 那个键值对
Typecript 类型
any、unknown、never、void、tuple、enum,以及两个⽤于⾃定义类型的⽅式:type、 interface
any
表示任意类型
// 可以接受任意类型的变量
let a: any
a = 100
a = '你好'
//可以赋值给任意类型的变量
let c:any
c = 9
let x: string
x = c
//可以调用任意属性
let str2: any
str2.toUpperCase()unknown
表示未知类型
let a: unknown
// 可以接受任意类型的变量
a = 100
a = false
// 但是不能将类型“unknown”分配给其他类型
let x: string
x = a
// 不能调用任意属性
let str3: unknown
str3.toUpperCase()
// 强制分配和调用属性方式
// 第⼀种⽅式:加类型判断
if(typeof a === 'string'){
x = a
console.log(x)
}
//第⼆种⽅式:加断⾔
(str3 as string).toUpperCase()
//第三种⽅式:加断⾔
x = <string>anever
不能有值,包括undefined 、 null
let a: never
// 均无法接受
a = true
a = undefined
// 一般存在于以下两种情况:
// 情况一:TypeScript推断
let a: string
// 给a设置⼀个值
a = 'hello'
if (typeof a === 'string') {
console.log(a.toUpperCase())
} else {
// TypeScript会推断出此处的a是never,因为没有任何⼀个值符合此处的逻辑
console.log(a)
}
// 限制throwError函数不需要有任何返回值,任何值都不⾏,像undeifned、null都不⾏
function throwError(str: string): never {
throw new Error('程序异常退出:' + str)
}void
含义是空,即函数不返回任何值,调⽤者也不应依赖其返回值进行任何操作!
// 函数没有返回时,但会有⼀个隐式返回值undefined,其是void可以接受的⼀种“空”
function logMessage():void{
//情况一:不return
//情况二:仅return
return ;
//情况三,return undefined
return undefined;
}
let result = logMessage()
// 返回undefined时,下述语句可以执行,返回void时,报错:⽆法测试 "void" 类型的表达式的真实性
if(result){
}Tuple
元组可以存储固定数量的元素,并且每个元素的类型是已知的且可以不同。
// 第⼀个元素必须是 number 类型,第二个元素是可选的,如果存在,必须是 boolean 类型。
let arr1: [number,boolean?]
// 第⼀个元素必须是 number 类型,后⾯的元素可以是任意数量的 string 类型
let arr2: [number,...string[]]
// 可以赋值
arr1 = ['hello',123]
arr2 = [100,'hello','world']enum
数字枚举
其成员的值会自动递增,且数字枚举还具备反向映射的特点。
enum Direction {
// 默认从0开始递增
Up,
Down,
//也可以指定其值,后续从5开始递增
Left=5,
Right
}
// 反向映射
console.log(Direction.Up)// 0
console.log(Direction[0])// 为Direction.Up,即0
// 此⾏代码报错,枚举中的属性是只读的
Direction.Up = 'shang'字符串枚举
enum Direction {
Up = "up",
Down = "down",
Left = "left",
Right = "right"
}
// 不支持反向映射
let dir: Direction = Direction.Up;
console.log(dir); // 输出: "up"常量枚举
使⽤ const 关键字定义,在编译时会被内联(将枚举成员引⽤替换为它们的实际值)。
const enum Directions {
Up,
Down,
Left,
Right
}
let x = Directions.Up;
//翻译为
"use strict";
let x = 0 /* Directions.Up */;type
type 可以为任意类型创建别名,同时能更方便进行类型复用和扩展。
基本用法
// 为number取别名为num
type num = number;
let price: num;
price = 100;联合类型
表示⼀个值可以是几种不同类型之⼀
// 类型可以为number或string
type Status = number | string
// 值仅可为男或女
type Gender = '男' | '⼥'
function printStatus(status: Status,str:Gender) {
}交叉类型
允许将多个类型合并为⼀个类型。合并后的类型将拥有所有被合并类型的成员。
// ⾯积
type Area = {
height: number; //⾼
width: number; //宽
};
// 地址
type Address = {
num: number; //楼号
cell: number; //单元号
room: string; //房间号
};
// 定义类型House,且House是Area和Address组成的交叉类型,需要传入所有属性
type House = Area & Address;
const house: House = {
height: 180,
width: 75,
num: 6,
cell: 3,
room: '702'
};类型声明
基本类型
let a: string //变量a只能存储字符串
let b: number //变量b只能存储数值
// 参数x必须是数字,参数y也必须是数字,函数返回值也必须是数字,且调用传入参数必须为两个
function demo(x:number,y:number):number{
return x + y
}
//a的值只能为字符串“你好”,b的值只能为100,不能再为其赋其他值
let a: '你好'
let b: 100
//自动类型推断
let d = -99 //TypeScript会推断出变量d的类型是数字
d = false //警告:不能将类型“boolean”分配给类型“number”对象声明
// 限制person1对象必须有name属性,age为可选属性
let person1: { name: string, age?: number }
// 含义同上,也能⽤分号做分隔
let person2: { name: string; age?: number }
// 含义同上,也能⽤换⾏做分隔
let person3: {
name: string
age?: number
}
// 限制person对象必须有name属性,可选age属性但值必须是数字,同时可以有任意数量、任意类型的其他属性
let person: {
name: string
age?: number
[key: string]: any // 索引签名,完全可以不⽤key这个单词,换成其他的也可以
}
// 如下赋值均可以
person1 = {name:'李四',age:18}
person2 = {name:'张三'}
person3 = {name:'王五'}
person4 = {
name:'张三',
age:18,
gender:'男'
}函数声明
let count: (a: number, b: number) => void
const func: count = (1,2) => {
// 注意,虽然限制了返回值为void,但是允许返回⾮空值
return 100;
};
//是为了确保如下代码成⽴,Array.prototype.push 的返回值是⼀个数字,⽽ Array.prototype.forEach ⽅法期望其回调的返回类型是 void。
const src = [1, 2, 3];
const dst = [0];
src.forEach((el) => dst.push(el));数组声明
let arr1: string[]
let arr2: Array<string>
arr1 = ['a','b','c']
arr2 = ['hello','world']类型约束文件
类型声明文件通常以 .d.ts 作为扩展名。它的主要作用是为现有的 JavaScript 代码提供类型信息,使得在使用这些js时可以对其进行类型检查。
// 添加类型检查文件后,使用js也会有类型提示
// 现有的js文件:demo.js
export function add(a, b) {
return a + b;
}
export function mul(a, b) {
return a * b;
}
// 类型解释文件:demo.d.ts
declare function add(a: number, b: number): number;
declare function mul(a: number, b: number): number;
export { add, mul };其他
数据解构
数组结构
let arr = [1, 2, 3];
// x,y,z 将与 arr 中的每个位置对应来取值
const [x, y, z] = arr;对象解构
const person = {
name: "jack",
age: 21,
language: ['java', 'js', 'css']
}
// 解构表达式获取值,将 person 里面每一个属性和左边对应赋值
const {name, age, language} = person;
// 将name属性赋值给personName
const {name: personName, age, language} = person;链判断
如果读取对象内部的某个属性,往往需要判断一下,属性的上层对象是否存在。
const firstName = message?.body?.user?.firstName || 'default';
// 等价于
const firstName = (message
&& message.body
&& message.body.user
&& message.body.user.firstName) || 'default';参数默认值
// 直接给参数写上默认值,没传就会自动使用默认值
function add2(a, b = 1) {
// 等价于 b = b || 1;
return a + b;
}箭头函数
// 只有一个参数可以不需要()
let print = obj => console.log(obj);
//当只有一行语句,并且需要返回结果时,可以省略 {} , 结果会自动返回。
let sum2 = (a, b) => a + b;
// 多行代码需要使用{}扩起
let sum3 = (a, b) => {
c = a + b;
return c;
};模板字符串
let info = `你好,我的名字是:${name},年龄是:${person.age},邮箱是:${person.email}`指数运算符
// 案例一:运算方式
2 ** 2 // 4
2 ** 3 // 8
// 相当于 2 ** (3 ** 2)
2 ** 3 ** 2 // 512解构赋值
Null判断运算符
类似||,但是只有运算符左侧的值为null或undefined时,才会返回右侧的值
null ?? 55; // 55
undefined ?? 55; // 55拓展运算符
取出数组和对象的所有属性
// 数组(对象同样可以)
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const mergedArray = [...arr1, ...arr2];
console.log(mergedArray); // 输出: [1, 2, 3, 4, 5, 6]
// 取出数组所有元素给函数
function sum(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 输出: 6
const person = { name: '李四', age: 18, city: '北京' };
const { name, ...rest } = person;
console.log(name); // 输出: 李四
console.log(rest); // 输出: { age: 18, city: '北京' }面向对象
类
基本使用
class Person {
// 属性声明
name: string
age: number
// 构造器
constructor(name: string, age: number) {
this.name = name
this.age = age
}
// ⽅法
speak() {
console.log(`我叫:${this.name},今年${this.age}岁`)
}
}
// 创建实例
const p1 = new Person('周杰伦', 38)继承
class Student extends Person {
// 子类新增属性
grade: string
// 构造器,若Student类不需要额外的属性,Student的构造器可以省略
constructor(name: string, age: number, grade: string) {
super(name, age)
this.grade = grade
}
// 重写从⽗类继承的⽅法
override speak() {
// 内部通过this调用
console.log(`我是学⽣,我叫:${this.name},今年${this.age}岁,在读${this.grade}年级`,)
}
// ⼦类⾃⼰的⽅法
study() {
console.log(`${this.name}正在努⼒学习中......`)
}
}封装
| 关键字 | 作用 |
|---|---|
| public | 可以被:类内部、子类、类外部访问 。 |
| protected | 可以被:类内部、子类访问。 |
| private | 可以被:类内部访问。 |
| readonly | 属性无法修改。 |
class Person {
// 按照下方规则使用,默认就是public修饰
public name: string,
// 只读属性可以与其他属性一起
public readonly age:number
// readonly属性仅能在构造器初始化时赋值
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
// 简化对象创建形式
class Person {
constructor(public name: string,public readonly age: number) {
}
}抽象类
抽象类不能实例化,其意义是可以被继承,抽象类里可以有普通方法、也可以有抽象方法。
abstract class Package {
constructor(public weight: number) { }
// 抽象⽅法
abstract calculate(): number
// 通⽤⽅法
printPackage() {
console.log(`包裹重量为: ${this.weight}kg,运费为: ${this.calculate()}元`);
}
}
// 实现抽象方法
class StandardPackage extends Package {
constructor(
weight: number,
public unitPrice: number // 每公⽄的固定费率
) { super(weight) }
// 实现抽象⽅法
calculate(): number {
return this.weight * this.unitPrice;
}
}
// 创建实例
const s1 = new StandardPackage(10,5)接口
只能定义格式,不能包含任何实现 !
- 相同点: interface 和 type 都可以用于定义对象结构,在定义对象结构时两者可以互换。
- 不同点:
- interface :更专注于定义对象和类的结构,⽀持继承、合并。
- type :可以定义类型别名、联合类型、交叉类型,但不⽀持继承和⾃动合并。
定义类结构
// 创建接口
interface PersonInterface {
name: string
age: number
speak(n: number): void
}
// 实现接口
class Person implements PersonInterface {
constructor(
public name: string,
public age: number
) { }
// 实现接⼝中的 speak ⽅法
speak(n: number): void {
for (let i = 0; i < n; i++) {
// 打印出包含名字和年龄的问候语句
console.log(`你好,我叫${this.name},我的年龄是${this.age}`);
}
}
}
// 创建⼀个实例
const p1 = new Person('tom', 18);定义对象结构
interface UserInterface {
name: string
readonly gender: string // 只读属性
age?: number // 可选属性
run: (n: number) => void
}
const user: UserInterface = {
name: "张三",
gender: '男',
age: 18,
run(n) {
console.log(`奔跑了${n}⽶`)
}
};定义函数结构
interface CountInterface {
(a: number, b: number): number;
}
const count: CountInterface = (x, y) => {
return x + y
}接口继承
interface PersonInterface {
name: string // 姓名
age: number // 年龄
}
interface StudentInterface extends PersonInterface {
grade: string // 年级
}
const stu: StudentInterface = {
name: "张三",
age: 25,
grade: '⾼三',
}接口自动合并
// 接口一
interface PersonInterface {
name: string
age: number
}
// 接口二
interface PersonInterface {
speak(): void
}
// Person类实现PersonInterface,会同时实现接口一和接口二
class Person implements PersonInterface {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
speak() {
console.log('你好!我是⽼师:', this.name)
}
}泛型
定义函数、类或接口时,使用类型参数来表示未指定的类型,这些参数在具体使⽤时,才被指定具体的类型。
// 泛型函数(单个泛型)
function logData<T>(data: T): T {
console.log(data)
return data
}
logData<number>(100)
logData<string>('hello')
// 泛型函数(多个泛型)
function logData<T, U>(data1: T, data2: U): T | U {
console.log(data1,data2)
return Date.now() % 2 ? data1 : data2
}
logData<number, string>(100, 'hello')
logData<string, boolean>('ok', false)
// 泛型接口
interface PersonInterface<T> {
name: string,
age: number,
extraInfo: T
}
let p1: PersonInterface<string>
p1 = { name: '张三', age: 18, extraInfo: '⼀个好⼈' }
// 泛型约束
interface LengthInterface {
length: number
}
// 约束规则是:传⼊的类型T必须具有 length 属性
function logPerson<T extends LengthInterface>(data: T): void {
console.log(data.length)
}
// 泛型类
class Person<T> {
constructor(
public name: string,
public age: number,
public extraInfo: T
) { }
speak() {
console.log(`我叫${this.name}今年${this.age}岁了`)
console.log(this.extraInfo)
}
}
type JobInfo = {
title: string;
company: string;
}
const p2 = new Person<JobInfo>("tom", 30, { title: '研发总监', company: '发发发科技公司' });AXIOS
get
axios.get('/user', {
// 携带请求参数
params: {
ID: 12345
}
})
.then(function (response) {
// 处理成功情况
console.log(response);
})
.catch(function (error) {
// 处理失败情况
console.log(error);
})
.finally(function () {
// 总是会执行
}); post
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});请求响应信息
{
// `data` 由服务器提供的响应
data: {},
// `status` 来自服务器响应的 HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: 'OK',
// `headers` 是服务器响应头
// 所有的 header 名称都是小写,而且可以使用方括号语法访问
// 例如: `response.headers['content-type']`
headers: {},
// `config` 是 `axios` 请求的配置信息
config: {},
// `request` 是生成此响应的请求
// 在node.js中它是最后一个ClientRequest实例 (in redirects),
// 在浏览器中则是 XMLHttpRequest 实例
request: {}
}请求配置
创建实例instance后,添加配置信息和拦截器后,后续操作通过实例执行
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
//可用的配置项如下:
{
// `url` 是用于请求的服务器 URL
url: '/user',
// `method` 是创建请求时使用的方法
method: 'get', // 默认值
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: 'https://some-domain.com/api/',
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 它只能用于 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream
// 你可以修改请求头。
transformRequest: [function (data, headers) {
// 对发送的 data 进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
// 对接收的 data 进行任意转换处理
return data;
}],
// 自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` 是与请求一起发送的 URL 参数
// 必须是一个简单对象或 URLSearchParams 对象
params: {
ID: 12345
},
// `paramsSerializer`是可选方法,主要用于序列化`params`
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// `data` 是作为请求体被发送的数据
// 仅适用 'PUT', 'POST', 'DELETE 和 'PATCH' 请求方法
// 在没有设置 `transformRequest` 时,则必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属: FormData, File, Blob
// - Node 专属: Stream, Buffer
data: {
firstName: 'Fred'
},
// 发送请求体数据的可选语法
// 请求方式 post
// 只有 value 会被发送,key 则不会
data: 'Country=Brasil&City=Belo Horizonte',
// `timeout` 指定请求超时的毫秒数。
// 如果请求时间超过 `timeout` 的值,则请求会被中断
timeout: 1000, // 默认值是 `0` (永不超时)
// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials: false, // default
// `adapter` 允许自定义处理请求,这使测试更加容易。
// 返回一个 promise 并提供一个有效的响应 (参见 lib/adapters/README.md)。
adapter: function (config) {
/* ... */
},
// `auth` HTTP Basic Auth
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// `responseType` 表示浏览器将要响应的数据类型
// 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
// 浏览器专属:'blob'
responseType: 'json', // 默认值
// `responseEncoding` 表示用于解码响应的编码 (Node.js 专属)
// 注意:忽略 `responseType` 的值为 'stream',或者是客户端请求
// Note: Ignored for `responseType` of 'stream' or client-side requests
responseEncoding: 'utf8', // 默认值
// `xsrfCookieName` 是 xsrf token 的值,被用作 cookie 的名称
xsrfCookieName: 'XSRF-TOKEN', // 默认值
// `xsrfHeaderName` 是带有 xsrf token 值的http 请求头名称
xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值
// `onUploadProgress` 允许为上传处理进度事件
// 浏览器专属
onUploadProgress: function (progressEvent) {
// 处理原生进度事件
},
// `onDownloadProgress` 允许为下载处理进度事件
// 浏览器专属
onDownloadProgress: function (progressEvent) {
// 处理原生进度事件
},
// `maxContentLength` 定义了node.js中允许的HTTP响应内容的最大字节数
maxContentLength: 2000,
// `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数
maxBodyLength: 2000,
// `validateStatus` 定义了对于给定的 HTTP状态码是 resolve 还是 reject promise。
// 如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),
// 则promise 将会 resolved,否则是 rejected。
validateStatus: function (status) {
return status >= 200 && status < 300; // 默认值
},
// `maxRedirects` 定义了在node.js中要遵循的最大重定向数。
// 如果设置为0,则不会进行重定向
maxRedirects: 5, // 默认值
// `socketPath` 定义了在node.js中使用的UNIX套接字。
// e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程。
// 只能指定 `socketPath` 或 `proxy` 。
// 若都指定,这使用 `socketPath` 。
socketPath: null, // default
// `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
// and https requests, respectively, in node.js. This allows options to be added like
// `keepAlive` that are not enabled by default.
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// `proxy` 定义了代理服务器的主机名,端口和协议。
// 您可以使用常规的`http_proxy` 和 `https_proxy` 环境变量。
// 使用 `false` 可以禁用代理功能,同时环境变量也会被忽略。
// `auth`表示应使用HTTP Basic auth连接到代理,并且提供凭据。
// 这将设置一个 `Proxy-Authorization` 请求头,它会覆盖 `headers` 中已存在的自定义 `Proxy-Authorization` 请求头。
// 如果代理服务器使用 HTTPS,则必须设置 protocol 为`https`
proxy: {
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// see https://axios-http.com/zh/docs/cancellation
cancelToken: new CancelToken(function (cancel) {
}),
// `decompress` indicates whether or not the response body should be decompressed
// automatically. If set to `true` will also remove the 'content-encoding' header
// from the responses objects of all decompressed responses
// - Node only (XHR cannot turn off decompression)
decompress: true // 默认值
}请求拦截
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});模块化
Common JS模块化
Node.js 默认是⽀持 CommonJS 规范的,但浏览器端不⽀持,所以需要经过编译 。所以主要应用于服务端
导出
- 每个模块内部的: this 、 exports 、 modules.exports 在初始时,都指向同⼀个空对象
- ⽆论如何修改导出对象,最终导出的都是 module.exports 的值。
- exports 是对 module.exports 的初始引⽤,仅为了⽅便给导出象添加属性,所以不能使⽤ exports = value 的形式导出数据,但是可以使⽤ module.exports= xxxx 导出数据。

const name = '尚硅⾕'
const slogan = '让天下没有难学的技术!'
function getTel()
{
return '010-56253825'
}
// 方式一
exports.name = name
exports.slogan = slogan
exports.getTel = getTel
// 方式二
module.exports.name = name
module.exports.slogan = slogan
module.exports.getTel = getTel
// 方式三
module.exports={name,slogan,getTel}导入
// 直接引⼊模块,通过school.xx使用
const school = require('./school')
// 引⼊同时解构出要⽤的数据
const { name, slogan, getTel } = require('./school')
// 引⼊同时解构+重命名
const {name:stuName,motto,getTel:stuTel} = require('./student')浏览器支持
第⼀步:全局安装 browserify : npm i browserify -g
第二步:编译
// index.js 是源⽂件, build.js 是输出的⽬标⽂件
browserify index.js -o build.js第三步:页面中引入使用
<script type="text/javascript" src="./build.js"></script>ES6模块化
浏览器与服务端均⽀持该规范 ,主要应用于浏览器端。
Node.js 中运⾏ ES6 模块代码有两种⽅式:
- ⽅式⼀:将 JavaScript ⽂件后缀从 .js 改为 .mjs ,Node 则会⾃动识别 ES6 模块。
- ⽅式⼆:在 package.json 中设置 type 属性值为 module
页面中引入
<!--通过script标签引入,需要指定type=module-->
<script type="module" src="./index.js"></script>导出
// 分别导出
export let name = {str: '尚硅⾕'}
export const slogan = '让天下没有难学的技术!'
export function getTel() {
return '010-56253825'
}
// 统⼀导出
const name = {str:'尚硅⾕'}
const slogan = '让天下没有难学的技术!'
function getTel (){
return '010-56253825'
}
export {name,slogan,getTel}
// 默认导出,导出的是一个对象
const name = '张三'
const motto = '⾛⾃⼰的路,让别⼈五路可⾛!'
function getTel (){
return '13877889900'
}
export default {name,motto,getTel}导入
// 全部导入
import * as school from './school.js
// 命名导入,对应分别导出、统⼀导出
import { name,slogan,getTel } from './school.js
import { name as myName,slogan,getTel } from './school.js' // as重命名
// 默认导入,对应默认导出。默认导出的名字可以修改,其是一个对象,通过这个对象调用导出属性。
import student from './student.js'
// 命名导⼊与默认导⼊混合使⽤,且默认导⼊的内容必须放在前⽅
export const name = {str:'尚硅⾕'}
export const slogan = '让天下没有难学的技术!'
function getTel (){
return '010-56253825'
}
export default getTel
import getTel,{name,slogan} from './school.js
// 动态导入
// 允许在运⾏时按需加载模块,在需要导入模块时再执行下方代码即可,返回值是⼀个 Promise。
const school = await import('./school.js');
// 仅运行js文件,不导入数据
import './mock.js'实际使用
防抖
在事件被触发的 n 秒后再执行,如果这 n 秒内又被触发,则重新计时。
- 按钮提交场景:防止多次提交按钮,只执行最后提交的一次
- 输入场景:搜索联想词功能类似
/**
* 防抖函数,可立即执行,可传参,但无返回值
* @param {Function} fn 需要防抖的函数
* @param {Number} delay 防抖的时间
* @param {Boolean} immediate 是否立即执行
* @returns
*/
const debounce = (fn, delay = 800, immediate = false) => {
let timer = null;
return function(...args) {
if(timer !== null) clearTimeout(timer);
if(immediate && timer === null) {
fn.apply(this, args);
timer = setTimeout(()=> timer = null, delay);
return;
}
timer = setTimeout(()=>{
fn.apply(this, args);
clearTimeout(timer);
timer = null;
}, delay)
}
}节流
在规定单位时间内,只能触发一次函数。如果多次触发则只生效一次。
/**
* 节流函数
* @param {Function} fn 需要节流的函数
* @param {Number} delay 节流的时间
* @returns
*/
const throttle = (fn, delay) => {
let previous = 0;
return function (...args) {
const now = Date.now();
if (now - previous > delay) {
previous = now;
return fn.apply(this, args);
}
}
}深拷贝
/**
* 数据类型:
* 1. 可以直接返回的:
* Number、String、Boolean、undefined、Symbol、BigInt、Function
* null(需要特殊判断)
*
* 2. 不可以直接返回的:
* Object、Array
* Object 的特殊细分类型:Date、RegExp
*
* 3. 避免循环引用
*/
const deepClone = (obj, hash = new WeakMap()) => {
if (obj === null) return obj
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
if (typeof obj !== 'object') return obj
if (hash.has(obj)) return hash.get(obj)
const target = Array.isArray(obj) ? [] : {}
hash.set(obj, target)
Reflect.ownKeys(obj).forEach(key => {
target[key] = deepClone(obj[key], hash)
})
return target
}有趣代码
可编辑网页
浏览器地址栏输入下方链接,可以作为记事本使用。解码后内容为:<html contenteditable></html>
data:text/html;base64,PGh0bWwgY29udGVudGVkaXRhYmxlPmVkaXQgaGVyZTwvaHRtbD4=浏览器控制台直接执行以下js代码,将可以编辑网页元素
document.body.contenteditable=true边框显示
[].forEach.call($$("*"),function(a){
a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)
})无限debug
setInterval(()=>{(a=>{try{((''+a/a).length!==1?1:1)&&Function('debugger')();a++&&arguments.callee(a)}catch{}})(0)},4000);