JavaScript语法

理想的语法

复用

循环:复用几乎相同的代码

函数:复用相同的代码

结构体/类:复用函数-属性的组合

类继承:复用已有的类

复合类型1

数组:有序、限长、同类型

Link集合:有序、不限长、任意类型

Set集合:无序、不限长、任意类型

复合类型2

Map集合:无序、不限长、任意类型

实例对象:无序、限长、预定义类型

函数式编程

函数式编程应是主流

类/结构体只是复合类型

函数和类的嵌套

函数中能定义函数、类

类中能定义函数、类

类型限制

类型约束、代码提示、性能提升

类型推断

变量赋值&定义:自动推断类型

函数定义:自动推导返回值类型

类型写法

类型前置,类型后置

any&Object

any类型:能指向任意类型

Object类型:能指向任意实例对象

编译运行

解释运行

编译功能:事先编译能大大提升性能

解释功能:边解释边执行

堆内存回收

手动释放、GC释放

动态类加载

JS的动态import,require

Java的反射机制

序列化

JS把对象转成JSON字符串

Java把对象转成二进制数据

注释

// 单行注释

/*

多行注释

*/

/**

*文档注释

*/

循环

for in迭代器

while循环

loop无限循环

判断

if-else、switch是判断表达式

case后面是条件判断,而非数据

模块化

模块A的首次引入

会运行模块A的代码

返回暴露对象a

并将暴露对象a缓存起来

模块A的后续引入

不会运行模块A代码

直接返回暴露对象a

写法优化

省略语句分号

模板字符串

剩余参数、默认参数、具名参数

箭头函数

对象访问:obj.属性名、obj.['属性名']

数组、对象、字符串的解构赋值

类型别名

通过代码生成公共代码

  • Rust:宏在编译期实现扩展
  • Java:注解+动态生成类,动态实现类的扩展
  • JS:eval运行动态拼接的代码字符串
  • JS:装饰器+babel转换,在打包时实现扩展

组合扩展结构体

结构体

支持定义实例属性、实例方法

支持定义静态属性、静态方法

接口

约定结构体的方法

多态

结构体B实现接口A方法1、2

创建接口A的引用变量a

创建结构体B的实例b

变量a能调用实例b的方法1、2

组合扩展

结构体A定义一些属性和方法

结构体B定义一些属性和方法

结构体C定义一些属性和方法

结构体C的属性中包含结构体A、B

结构体C即对是结构体A、B的扩展

继承扩展类

  • 类有结构体的特性:定义实例方法、实例属性
  • 类有接口的特性:定义抽象方法
  • 类的继承是一种规范化的组合
  • 类能继承或实现类的抽象方法
  • 类能继承或重写类的实例方法、实例属性

简单对比

  • 接口:静态属性、静态方法,抽象方法
  • 抽象类:静态属性、静态方法,抽象方法,普通方法,普通属性
  • 普通类:静态属性、静态方法,普通方法,普通属性

Java单继承

  • 普通类单继承普通类、普通类单继承抽象类、普通类多实现接口
  • 抽象类单继承抽象类、抽象类多实现接口
  • 接口多继承接口

C++多继承

  • 普通类多继承普通类、普通类多继承抽象类
  • 抽象类多继承普通类、抽象类多继承抽象类

变量-类型

强弱类型语言

静态强类型动态弱类型

函数参数

函数返回值

参数个数固定

参数类型固定

返回值类型固定

重载扩展:支持定义不同形参的同名函数

泛型扩展:动态指定参数和返回值类型

形参不同=>参数个数或参数类型不同

参数个数随意

参数类型随意

返回值类型随意

变量指向

类变量能指向本类实例

多态的扩展:

    类变量能指向后代实例

    类变量能调用后代实例重写的方法

    类变量不能调用后代实例扩展的方法

变量指向任意类型
权限修饰符

private、protect、public

性能更高较低
IDE提示依据

变量类型,返回值类型,参数类型

XXXDom注释

XXXDom注释

权限修饰符 

  • private:支持本类内部访问
  • protect:支持本类和子类内部访问
  • public:支持本类和子类内部访问,支持类实例访问
  • 若子类方法抛出的异常大于父类,可能发生try-catch能处理父类方法的异常,但是不能处理子类抛出的异常。所以子类方法抛出的异常不能大于父类抛出的异常
  • 若子类方法的访问权限小于父类,可能发生父指针能调用父类方法,但不能调用子类方法。所以子类方法的访问权限必须大于父类方法的访问权限

泛型的使用

class rapList<T>{               //类上定义
    public String rap<D>(){     //方法上定义
        D d;                    //泛化属性类型
        return "阿坤";
    }
    public T rap(T name){       //泛化方法返回值
        return name;
    }
}

JavaScript类型

语言类型

JS:动态弱类型

TS:类型限制的动态弱类型

值类型

大整型:bigInt

浮点型:number

布尔型:boolean

undefined、null、symbol、string

引用类型

集合、数组、普通对象、函数

判断类型

let res=typeof xxx

res的类型是字符串

res的值是变量xxx的类型

变量声明

let k1:number=v1,k2=v2

类型推断、后置类型

局部性死区

变量声明后,才能使用

常量

const

x的if条件为假

Bollean(x)为false

!!x为false

布尔值:false

数字:0

空字符串:""

特殊值:null、undefined、NaN

模板字符串`${变量}字符${变量}`
n进制

数字类型全部是十进制

字符串存放其他进制数字

 枚举

Javascript:枚举名是实例对象,枚举属性是常量,枚举属性是基本数据类型

enum Gender{male='男',female='女',unknown='未知'}
console.log(Gender)  //{male:'男',female:'女',unknown:'未知'}

enum Gender{male,female,unknown}
console.log(Gender)  //{male:0,female:1,unknown:2}

let info:{name:string,gender:Gender}
//info.gender的值只能是Gender.male、Gender.female、Gender.unknown

Java:枚举名是类名,枚举属性是类的静态属性,枚举属性是对象

public enum Gender {
    male("male1","male2","male3"),
    female("fmale1","fmale2","fmale3"),
    unknown("unknown1","unknown2","unknown3");

    public String str1;
    public String str2;
    public String str3
    Gender(String str1,String str2,String str3){
        this.str1=str1;
        this.str2=str2;
        this.str3=str3;
    }
}

Gender.female
    Gender.female是Gender类型对象
    Gender.female.toString()=='female'
    Gender.female.str1=male1
    Gender.female.str2=male2
    Gender.female.str3=male3

type

定义函数类型type Add=(a:number , b:number) => number
定义对象类型type Point<T>={ x?:T ;  readonly y:number }
重命名类型type Num=number
联合类型

type Status="success" | "fail" | "pending"

type Result=string | number

交叉类型type Person=Student & Children

语句&运算符

概述

条件语句

for、if-else、switch

switch(value){
    case matchValue1:
        语句1;
        语句2;
        break;
    case matchValue2:
        语句1;
        语句2;
        break;
    default:
        语句1;
        语句2;
        break;
}

扩展运算符{...obj,sex:'男'}、[..arr,'男']
解构赋值

单层:

    let [name,age]=arr        
    let {name,age}=obj

多层解构:    
    let [[sex1,sex2],age]=arr 
    let {sex:{sex1,sex2},age}=obj 
重命名:

    let {name,age:rAge}=obj

默认值:

    let {name="Tom",age}=obj

==和===

==:会做类型转换

===:不会做类型转换,更严格

终止关键字

break:终止循环语句

continue:结束循环语句当前迭代

break无法终止try-catch、if-else

return:结束函数

简化写法

普通写法JS简写

if(isTrue){

    c=a+b

    return

}

if(isTrue) return c=a+b

if(isTrue) {c=a+b}

if(isTrue) c=a+b
promise thenasync await
obj.name?.reallyName   
arr[1]?.[1]

obj.name!=null?

    obj.name.reallyName:

    undefined

arr[1]!=null?

    arr[1].[1]:

    undefined

{ age:age}

{age}

  • { fn(){} }写法基本等效于{ fn:function(){} },但是{ fn{} }写法中的fn不能作为构造函数使用
  • { fn:()=>{} }是箭头函数写法,与上面两种差距明显

a++ & ++a

  1. let a=0
  2. console.log(a++) :输出0;先赋值,再加1
  3. console.log(++a):输出1;先加1,再赋值

&&-||-?? 

a && b && ca失败,返回a
a成功,判断b:b失败,返回b
b成功,判断c:c失败,返回c
c成功,返回c
a || b || ca成功,返回a
a失败,判断b:b成功,返回b
b失败,判断c:c成功,返回c
c失败,返回c
a ?? b

a不是null或undefined,返回a

a是null或undefined,返回b

>  <  == 

2>1true;比较数字大小
'b'>'a'

true;比较Unicode码大小

UTF-8、UTF-16 和 UTF-32 都是 ASCII 的超集

Javascript采用UTF-8

'a'>1 ==> NaN>1false;NaN与任何数据比较,都返回false
== 等值组一0、""、[]、false
== 等值组二null、undefined
NaN

NaN与任何值比较,都为false

a?b:c 

a?b:ca?
    b:
    c

if(a) b

else c

a?b?e:f:c?g:h
    

a?
    b?
        e:
        f:
    c?
        g:
        h

if(a){
    if(b) e
    else f
}else{
    if(c) g

    else h
}

num>50?num>75?log('大于75'):log('50~75'):num>25?log('25~50'):log('小于25')
 

num>50?
    num>75?

        log('大于75'):
        log('50~75'):
    num>25?
        log('25~50'):
        log('小于25')

if(num>50){
    if(num>75) log('大于75')
    else log('50~75')
}else{
    if(num>25) log('25~50')
    else log('小于25')
}

函数

概述

函数属性

fun.length :参数个数

fun.name:函数名称
arguments:(类数组){"0":1,"1":2,"2":3}

创建实例

{...}、new fun(...args)

剩余参数

function fun( a, b, ...args )

默认参数

function fun( a=1, b=2 )

作用域链层层向上寻找对应变量

副作用

纯函数:相同的输入=>相同的输出

副作用函数:相同的输入=>可能不同的输出

简化写法

普通写法JS简写

(age)=>{return age}

age=>age

()=>{console.log(123)}

()=>console.log(123)

function t(a,b){return a+b}

(a,b)=>a+b

立即执行函数

  • 作用:不用写变量名,避免变量污染
  • 写法:;(function(){...})()
  • 等效写法:function test(){...};test()

箭头函数

  • 写法:()=>{}
  • 不能作为构造函数使用
  • 没有自己的this
  • this继承自上层函数作用域
  • bind、apply、call无法修改它的this指向
  • 没有arguments对象,能用剩余参数解决
  • 没有prototype对象

装饰器函数

类装饰器

唯一参数ClassVar:ClassVar==被装饰的类对象

返回值:void || ClassVar的子类;代替当前类

方法装饰器

参数1(Object):类原型对象

参数2(string):当前方法名

参数3:{

        value:当前方法,

        writable:true,

        enumerable:true,

        configurable:true

}

返回值:void || PropertyDescriptor;代替当前方法

属性装饰器

参数1(Object):类原型对象

参数2(string):当前属性名

返回值:void || PropertyDescriptor;代替当前属性

参数装饰器

参数1(Object):类原型对象

参数2(string):当前方法名

参数3(number):当前参数在参数列表的索引

JavaScript类和继承

概述

  • 支持函数中定义函数、类
  • 支持类中定义函数、类
  • 构造方法写法:constructor(){}
  • 构造方法必须调用super(...args)
  • 无内部代码块
  • 静态属性无法继承
  • 访问对象属性的方式:obj.属性名、obj.['属性名']

属性划分

  • 6301742c8ac64dd6a350de9d2e7fc775.jpeg

  • 原型对象挂载:成员方法
  • 实例对象挂载:成员变量
  • 函数对象挂载:静态变量和静态方法
  • 实例对象.__proto__==函数对象.prototype==原型对象
  • 函数对象的静态属性,属于函数对象本身
class Cat{}

静态变量和静态方法挂载到Cat上

成员方法挂载到Cat.prototype上

const cat=new Cat()

成员变量挂载到cat上

cat.__proto__=Cat.prototype

constructor函数的this指向cat

调用constructor

构造方法

  • 默认实现无参构造:constructor(){super()}
  • 自定义的构造方法,必须显式调用super(...args)

2527c505e89846078ade23597416d236.jpeg

整合式继承成员属性

  • 子类实例存有自己和祖先的成员变量
  • 成员变量若重名,只保留最近的成员变量

链式继承成员方法

  • 子类原型存有自己的成员方法
  • 祖先原型存有自己的成员方法

3b03835c7b774910bba125c356b1ad06.png

链式继承原型属性

对象son链式查找变量xxx

son.xxx

son.__proto__.xxx

son.__proto__.__proto__.xxx

.......

xxx instanceof yyy

xxx.__proto__.constructor == yyy

xxx.__proto__.__proto__.constructor == yyy

......

Java类和继承 

概述

  • 支持函数中定义类
  • 支持类中定义函数、类
  • 构造方法写法:类名(){}
  • 构造方法必须调用super(...args)
  • 支持类中定义内部代码块和静态代码块
  • 代码块无法继承 
  • 访问对象属性的方式:obj.属性名

属性划分

  • 实例对象:成员变量、成员方法
  • 类对象:静态变量、静态方法

构造方法

  • 默认实现无参构造:类名(){}
  • 构造方法未显式调用super(...args),则会隐式调用super()
  • 构造方法未显式调用this(...args),进而间接调用super(...args),则会隐式调用super()

包裹式继承成员属性

d6f1d0cc885243cd8e9b6a9ebd740b57.jpeg

链式继承静态属性

类Son链式查找静态变量xxx

Son.xxx

Father.xxx

Grandfather.xxx

实例son链式查找静态变量xxx

son.xxx

Son.xxx

Father.xxx

Grandfather.xx

JavaScript对象

概述

  • 数据属性:enumerable、configurable、writable、value
  • 访问器属性:enumerable、configurable、get方法、set方法
  • 数据属性可以值本类型、引用类型
  • 访问器的返回值可以是值类型、引用类型

字面量设置

const info={
    fun:function(){},
    fun2(){},
    _age:43,
    get age(){
        return this._age
    },
    set age(newVal){
        this._age=newVal
    }
}

console.log(info)

{

    fun: [Function: fun],
    fun2: [Function: fun2],
    _age: 43,
    age: [Getter/Setter]

}

defineproperty设置

Object.defineproperty(obj,prop,configuration)

  • obj:对象
  • prop:对象属性
  • configuration:配置对象

configuration的属性

  1. enumerable:可遍历;configurable:可再次修改configuration
  2. writable:可重写;value:当前值
  3. get、set方法
  4. 2和3不能同时存在
const info={}
let _name="Tom"
Object.defineProperty(info,'age',{
    configurable:true, 
    enumerable:true,
    writable:true,
    value:43
})

Object.defineProperty(info,'name',{
    configurable:true, 
    enumerable:true,
    get(){
        return _name
    },
    set(newVal){
        _name=newVal
    }
})

console.log(info)

{

  age: 43,

  name: [Getter/Setter]

}

对象作用域

JS&Java&this指向

  • this指向方法所属对象;谁调用我,我指向谁
  • child.func():对象child调用自己的方法func,func的this指向对象child
  • child.func():对象child调用父类father的方法func,func的this指向对象child
  • child.func():对象child调用爷类grandFather的方法func,func的this指向对象child
  • func():JS&严格模式下,this指向undefined
  • func():JS&非严格模式,this指向window/globalThis
  • 构造方法的this指向实例对象obj
  • 静态方法没有this

JS&改变的this指向

  • obj.fun.call(child,arg1,arg2...):this指向child
  • obj.fun.apply(child,[arg1,arg2...]):this指向child
  • fun2=obj.fun.bind(child):方法fun2的this指向child
  • Reflect.get(target,key,receiver):target对象中,getter函数的this指向receiver

JS&手写的call方法

function call(fun,thisObj,...args){
    thisObj.fun=fun
    thisObj.fun(...args)
}

JS&super指向

  • Faher中定义fun,fun中的super指向Father.prototype
  • super的指向与xxx.fun()的xxx无关
class Father{
    fun(){super.xxx}
}

JS模块化概述

<script type="text/javascript">写法

  1. script标签们,按序依次运行
  2. 因为script标签作用域的var变量、function xxx(){},会挂载到window对象上
  3. 所以script标签间的作用域,互通且平级

C语言无模块化

  1. 编写A.c、B.c、C.c三个文件
  2. 把三个文件编译成可执行文件run.exe
  3. 从入口文件的main函数开始运行
  4. 三个文件的顶层作用域,互通且平级
  5. 顶层作用域只能定义函数和变量
  6. 同名函数能定义一次,声明多次
  7. 同名变量能定义一次,声明多次

C++的module模块化

  • 所有模块的首行:export module 模块名
  • 导出语法:export 变量名/函数名
  • 导入语法:import 模块名
  • 模块名不能重复

模块分类 

引入方式内容
自定义模块相对路径、绝对路径、文件名第三方模块、自己封装的模块
内置模块文件名fs、path、http模块等
内置对象无需引入

Object、Array、String、Math、Date

函数作用域

父函数中定义子函数

  1. 在FatherFn函数中定义ChildFn函数
  2. 把ChildFn函数传入UncleFn函数
  3. 在UncleFn函数中调用ChildFn函数
  4. 函数ChildFn的父级作用域仍是Father函数作用域

父函数中定义对象.子函数

  1. 在FatherFn函数中定义ChildObj对象,ChildObj对象定义ChildFn函数
  2. 把ChildObj对象传入UncleFn函数
  3. 在UncleFn函数中调用ChildObj.ChildFn函数
  4. ChildFn函数的父级作用域仍是Father函数作用域

Other

  • 把FatherFn、UncleFn换成FatherModule,UncleModule。效果类似
  • 父函数中定义子函数:会发生函数提升
  • 子函数调用的时候,才会真正与父作用域发生关联

模块引入策略

绝对路径引入import {xx,yy} from 'file://绝对路径'
相对路径引入

import {xx,yy} from './xxx'

相对的基准是:当前JS文件

文件名引入

import Vue from 'vue'

在 内置模块 中寻找Vue

在 当前目录/node_modules/vue 中寻找Vue

在 上层目录/node_modules/vue 中寻找Vue

……

顶级目录依旧没找到,报错

路径最后一级

是xxx.js文件,取xxx.js文件

是xxx文件夹,取xxx的入口文件

CommonJS&&ES6

node中,CommonJS转ES6

  • 方式一:把xxx.js后缀改为xxx.mjs
  • 方式二:在package.json中添加 "type": "module"

require导入

  • 动态导入
  • 运行过程中,遇到require语句,就进行导入操作

import导入

  • 静态导入
  • import语句会提升到文件头部
  • 先理清导入顺序,再运行代码
  • 最先导入的文件,最后运行

eval(str)实现动态生成代码

  • 参数str:string字符串
  • str字符串格式:str字符串必须符合js代码规范
  • 返回值:str中最后一个语句的值
  • str代码的作用域<=>调用eval函数的作用域

CommonJS模块化

导入导出

导出变量

module.exports={...}

module.exports.xxx=yyy

导入变量

const xxxExports=require('xxx')

xxxExports==module.exports

module和require

console.log(module)

PS C:\Users\Administrator\Desktop\many_env\my_node> node .\test.js

Module {
  '9': [Function: internalRequire],
  id: '.',
  path: 'C:\\Users\\Administrator\\Desktop\\many_env\\my_node',
  exports: {},
  filename: 'C:\\Users\\Administrator\\Desktop\\many_env\\my_node\\test.js',
  loaded: false,
  children: [],
  paths: [
    'C:\\Users\\Administrator\\Desktop\\many_env\\my_node\\node_modules',
    'C:\\Users\\Administrator\\Desktop\\many_env\\node_modules',
    'C:\\Users\\Administrator\\Desktop\\node_modules',
    'C:\\Users\\Administrator\\node_modules',
    'C:\\Users\\node_modules',
    'C:\\node_modules'
  ]
}

console.log(require)

PS C:\Users\Administrator\Desktop\many_env\my_node> node .\test.js

[Function: require] {
  resolve: [Function: resolve] { paths: [Function: paths] },
  main: Module {...},
  extensions: [Object: null prototype] {
    '.js': [Function (anonymous)],
    '.json': [Function (anonymous)],
    '.node': [Function (anonymous)]
  },
  cache: [Object: null prototype] {
    'C:\\Users\\Administrator\\Desktop\\many_env\\my_node\\test.js': Module {...}
  }
}

console.log(arguments)

PS C:\Users\Administrator\Desktop\many_env\my_node> node .\test.js

[Arguments] {
  '0': {},
  '1': [Function: require] {...},
  '2': Module {...},
  '3': 'C:\\Users\\Administrator\\Desktop\\many_env\\my_node\\test.js',
  '4': 'C:\\Users\\Administrator\\Desktop\\many_env\\my_node'
}

手写require

function myRequire(filename){
    
    //将filename转换成绝对路径
    switch(filename){
        case 绝对路径: break
        case 相对路径: filename=path.resolve(filename);break
        case 文件名: filename=toAbs(filename);break
    }    
    
    for(cacheItem in myRequire.cache){
        if(cacheItem==filename) return myRequire.cache[filename].exports
    }

    const pathname=path.dirname(filename)
    const code=fs.readFileSync(filename,'utf8')
    const module={
        id:filename,
        filename,
        path:pathname,
        exports:{},
        loaded:false
    }
    eval(`
        function callFn(exports,myRequire,module,__filename,__dirname){
            ${code}
        };
        callFn(module.exports,myRequire,module,filename,pathname)    
    `)
    module.loaded=true
    myRequire.cache[filename]=module
    return module.exports
}

ES6模块化 

 导入写法

  • impor导入的数据,用常量来接收
  • 批量导入:import { xxx as xx , yyy , default as dd } from 'zzz'
  • 统一导入:import * as xxx from 'yyy'(包含default)
  • 默认导入:import xxx from 'yyy'
  • 动态导入 :let result=import('./xxx');result是promise对象 

导出写法

  • 批量导出:export { xxx as xx , yyy , zzz as default }
  • 定义导出:export let key=value
  • 默认导出:export default variable
  • 导出命名变量:export * from 'yyy'(不包含default)
  • 导出默认变量:export { default } from  'vvv'
  • 批量导出:export { xxx as xx , yyy , default as zz } from 'vv'

导入JSON

  • 静态引入json:import json from './package.json' assert {type:'json'}
  • 动态引入json:let json=await import('./package.json',{assert :{type:'json'}}) 

import对象

  • import.meta.url:当前模块绝对目录

Java模块化

类即是模块

静态导入

导入方式内容
自定义模块

需要配置classpath

需要写包名

classpath路径下的class文件
内置模块

无需配置classpath

需要写包名

JAVA_HOME\lib\src下class文件
内置类

无需配置classpath

不用写包名

JAVA_HOME\lib\src\java.base\java\lang下class文件

使用同包的类类名
使用不同包的类

包名.类名

(import 包名)+类名

动态导入(反射机制)

动态类加载

  1. main方法执行前,会提前加载把需要的类加载到内存中
  2. main方法运行时,反射机制能动态的把需要的类加载到内存中

面向字节码编程

  • 字节码能生成类构造方法对象、类属性对象、类方法对象
  • 类构造方法对象能生成类实例
  • 类方法对象、类属性对象能突破访问修饰符和多态的限制
  • 类方法对象可以获取注解信息,进而根据注解信息为类添加相应功能

字节码对象

  • 包目录:类字节码.getProtectionDomain().getCodeSource().getLocation().getPath()
  • 包名:类字节码.getPackageName()

动态生成类

  1. 动态拼接一个字符串类,并转成二进制码
  2. 把二进制码编译成Java字节码
  3. 虚拟机动态读取Java字节码

JS微任务和宏任务

分类

  • 放入微任务:Promise,queueMicrotask
  • 放入宏任务:setTimeout,setInterval,读取文件回调,ajax回调

运行过程

  • 把同步代码,加入宏任务队列
  • 取出一个宏任务(首次即同步代码)运行,
  • 取出所有微任务运行
  • 取出一个宏任务运行
  • 取出所有微任务运行
  • ....
  • 直到宏任务和微任务队列都没有可执行代码

Promise构造

Promise {
    [[PromiseState]]: 'fulfilled',
    [[PromiseResult]]: 123,
    Symbol(async_id_symbol): 5,
    Symbol(trigger_async_id_symbol): 1
}

new Promise

let pro=new Promise((res,rej)=>{
    res(value) 或 rej(value) 或 throw new Error(value) 或 都不满足
})
调用res(value)

value是非promise对象:

    pro是成功的promise对象

    pro的PR==value

value是promise对象:

    pro的值取决于value

调用rej(value)

pro是失败的 promise

pro的PR==value

抛出错误

pro是失败的promise对象

rej()未调用

res()未调用

没有抛出错误   

pro是未定义的promise对象 

取决于 value的含义:

value是成功的 promise对象
        pro 是成功的promise对象

        pro的PR==value的PR

value是失败的 promise对象
        pro 是失败的 promise对象

        pro的PR==value的PR

value是未定义的promise对象
        pro 是未定义的promise对象       

Promise.resolve

let pro=Promise.resolve(value) //相当于 res(value)

value是非promise对象

    pro是成功的promise对象

    pro的PR==value

value是promise对象

    pro的值取决于 value

Promise.reject

let pro=Promise.reject(value) //相当于 rej(value)
  • pro是失败的promise
  • pro的PR==value

Promise.all

let p=Promise.all([p1,...,pn])

p1~pn有失败的promise

    p是失败的promise

    p的PR==首个失败promise的PR

p1~pn无失败的promise

    p是成功的promise

    p的PR==[p1的PR,…,pn的PR]

Promise.race

let p=Promise.race([p1,...,pn])
  • pj最先改变状态
  • p的状态==pj的状态
  • p的PR==pj的PR

async函数 

async function fn(){
    let result=await Promise.resolve(promiseValue)
    return value
}
let pro2=fn()

xxx.yyy(async ()=>{
    let result=await zzz.hhh()
    return value
})
  • await前面的语句同步执行
  • await后面的语句异步执行
  • 函数执行时报错,pro2是失败的promise对象

return的value是非promise对象

    pro2是成功的promise

    pro2的PR==value

return的value是promise对象

    pro2的值取决于value

顶级await使用条件

  • node版本:15+
  • package.json配置:"type": "module"
  • tsconfig.json配置:"module": "esnext", "target": "es2017+"

Promise回调

pro.then回调

函数返回值为undefined的情况

  • 函数中未显式调用 return xxx
  • 函数中显式调用 return
  • 函数中显示调用 return undefined
let pro2=pro.then((resValue)=>{   //funOne
    return value
},(rejValue)=>{                   //funTwo
    return value
})

回调函数的选择

pro是成功的promise

    调用funOne

    resValue==pro的PR

pro是失败的promise&&存在funTwo

    调用funTwo

    rejValue==pro的PR

pro是失败的promise&&不存在funTwo

    pro2是失败的promise

    pro2的PR==pro的PR

pro是未定义的promise

    不调用回调函数

    pro2是未定义的promise对象

运行回调函数

return的value是非promise对象

    pro2是成功的promise对象

    pro2的PR==value

return的value是promise对象

    pro2的值取决于 value

回调函数执行时报错

    pro2是失败的promise对象         

pro.catch回调

let pro2=pro.catch((rejValue)=>{return value}) 

是否运行回调函数

pro是成功的promise

    不运行回调函数

     pro2是成功的promise

     pro2的PR==pro的PR

pro是失败的promise

     执行回调

运行回调函数

return的value是非promise对象

     pro2是成功的promise

     pro2的PR==value

return的value是promise对象

     pro2的值取决于value

回调函数执行时报错

     pro2是失败的promise对象

Promise强化

 实现Promise

class MyPromise {
    constructor(executor) {
        this.state = 'pending';
        this.resultVal = null;
        this.onResolveCallbacks = [];
        this.onRejectCallbacks = [];

        const resolve = (value) => {
            queueMicrotask(() => {
                if (this.state === 'pending') {
                    this.state = 'fulfilled';
                    this.resultVal = value;
                    this.onResolveCallbacks.forEach(callback=>{
                        callback(this.resultVal
                    });
                }
            })
        };

        const reject = (error) => {
            queueMicrotask(()=>{
                if (this.state === 'pending') {
                    this.state = 'rejected';
                    this.resultVal = error;
                    this.onRejectCallbacks.forEach(callback=>{
                        callback(this.resultVal
                    )};
                }
            })
            
        };

        try {
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }

    then(onResolve, onReject) {
        return new MyPromise((resolve, reject) => {
            this.onResolveCallbacks.push((resultVal) => {
                try {
                    const result = onResolve(resultVal);
                    resolve(result);
                } catch (error) {
                    reject(error);
                }
            });
            this.onRejectCallbacks.push((resultVal) => {
                try {
                    const result = onReject(resultVal);
                    resolve(result);
                } catch (error) {
                    reject(error);
                }
            });
        });
    }
    catch(reject) {
        return this.then(null, reject);
     }
}

异步回调转同步

function awaitImgUpload() {
  return new Promise((resolve, reject) => {
    
    const observableImg = qiniu.upload(
        tempImgFile.value.raw, 
        imgStore +
        moment().format('YY/MM/DD/HH:mm:ss/') + 
        tempImgFile.value.name, uploadToken.value, 
        {}, 
        {}
    )

    observableImg.subscribe({
      next(res) {
        console.log(res)
      },
      error(err) {
        reject(err)
        ElMessage.error("图片上传失败")
      },
      complete(res) {
        resolve(res.key)
        ElMessage.success("图片上传成功")
      }
    
    })
  })
}

async function test(){
    const result=await awaitImgUpload()
    ......  //在七牛云图片上传完成后,要做的逻辑
}

forEach/Async1

function test(){
    arr.forEach(async (item)=>{  //async的正确放入方式
        await ......
    })
}

forEach/Async2

function wait() {
    return new Promise(resolve =>
        setTimeout(resolve, 2000));
}
function myForEach(arr, fn) {
    for (let i = 0; i < arr.length; i++) {
        fn(arr[i])
    }
}
const arr=["a","b"]

async function main1() {
   console.log("Start");
   arr.forEach(async (item) => {
      await wait()
      await console.log(item)
   })
   console.log("End")
}

async function main2() {
    console.log("Start");
    for (let i = 0; i < arr.length; i++) {
        await wait()
        await console.log(arr[i])
    }
    console.log("End");
}

async function main3() {
    console.log("Start");
    myForEach([1, 2], async (item) => {
        await wait()
        await console.log(item)
    })
    console.log("End")
}

//main1()
//main2()
//main3()

等待三秒 

new Promise(resolve => setTimeout(resolve, 3000));

Java多线程

run方式的实现

  • 继承的方式:重写run方法
  • 传参的方式:传入run方法

996c89fc2f8d4026ad1edb66893a8046.jpeg

线程状态

ebf0ca2be2d34878b637e86ae32fa886.jpeg

线程等待API 

  • Thread.yield():当前线程主动让出时间片
  • Thread.sleep(time):当前线程交出时间片,并休眠time毫秒
  • myThread.join():当前线程主动阻塞,直到myThread线程完成
  • 锁对象.await():当前线程主动阻塞,直到被唤醒;只能在同步语句中使用
  • myThread.interrupt():给线程打上true标识
  • Tread.interrupted():判断当前线程的标识,并把线程标识设置为false
  • 线程等待遇到true标识=>会结束等待&抛出异常&标识设为false
  • 锁对象.notify():唤醒await阻塞的线程;只能在同步语句中使用

Thread对象信息设置API

  • Thread myThread=new Thread()
  • Thread.currentThread()==myThread:获取当前线程
  • myThread.start():开启一个线程(一个myThread实例只能调用一次start方法)
  • myThread.setName(str):设置线程名称    
  • myThread.getName():获取线程名称
  • myThread.threadId():获取线程id
  • myTread.setPriority(1~10):设置线程优先级
  • myTread.getPriority:获取线程优先级
  • myTread.isAlive():线程在运行=>true;线程未开启或结束=>false
  • myThread.setDaemon():设置成守护线程,前台进程结束=>程序结束=>守护进程结束

必要性

public class Main {
    public int num=0;
    public void add(){
        for (int i=0;i<10000;i++){
            num++;
        }
    }
    public static void main(String[] args) {
        Main main = new Main();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                main.add();
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                main.add();
            }
        });
        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(main.num);
    }

}

运行结果:main.num<=20 000
  1. 线程1读取num=100
  2. 线程2读取num=100
  3. 线程1执行num=100+1=101
  4. 线程2执行num=100+1=101
  5. num本应等于102,由于上述原因导致num数值变小

概述

  • 乐观锁:能直接访问修改数据;写回修改数据时,会验证其它线程是否已修改数据
  • 悲观锁:获得锁后,才能访问修改数据

synchronized锁

class Main{
    Obj obj=new Obj();
    
    //同步代码块,锁对象是obj对象
    public void show1(){
        synchronized(obj){
            ......
        }
    }

    //同步实例方法,锁对象是Main实例对象
    public synchronized void show2(){
        ......
    }

    //同步静态方法,锁对象是Main.class
    public synchronized static void show3(){
        ......
    }
}

同步代码块、同步方法运行结束,会释放锁
同步代码块,同步方法抛出异常,会释放锁

ThreadLocal

5014746ec0f4481fb40b5c2c10a8d131.jpeg

线程池和数据库连接池

  • 服务器开启,会创建线程池和连接池
  • 用户发送请求,会从池中取出线程对象和连接对象
  • 服务器完成响应,会把连接对象和线程对象放入池中

Map<Thread,Connection>

  • 单次请求调用的servlet的线程对象是同一个
  • 为确保连接对象也是同一个,我们把线程对象和连接对象以键值对的形式存到Map集合中
  • 服务器完成响应时,需要把响应的键值对从Map集合中除去

异常

种类

  • 普通异常:如果捕捉并处理,能避免程序崩溃
  • 无解异常:无法处理,程序直接崩溃

处理普通错误

  • try捕捉异常,catch处理错误
  • 向上抛出异常(JavaScript会自动上抛)

try-catch-finally

t-c-f

t-f

try语句块未发生异常

执行finally语句

t-c-f

try语句块发生异常

try语句块后面的代码不再执行

默认生成异常对象

把异常对象传入catch语句块

执行catch语句块

执行finally语句

t-f

try语句块发生异常

try语句块后面的代码不再执行

默认生成异常对象

执行finally语句

把异常对象向上抛出

无t-c-f

发生异常

默认生成异常对象

把异常对象向上抛出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stealPigs-youth

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值