JS
浏览器的进程与线程
js在浏览器的编译过程
绝大多数编译器以预先编译(AOT)或实时编译(JIT)形式工作。
- 使用命令行或者集成开发环境(IDE)调用预先编译(AOT)的编译器,如 gcc
- 实时编译器通常是用来提高性能的,令你没有感知的,如 V8
V8 引入了即时编译(JIT)的双轮驱动的设计(混合使用编译器和解释器的技术),这是一种权衡策略,给 JavaScript 的执行速度带来了极大的提升。
垃圾回收
老生代:
标记清除
- 遍历
所有的对象找活动对象做标记 - 遍历所有的对象清除没有标记的对象
- 回收相应空间
缺点
- 清除过之后留下的是
碎片空间而不是连续空间,还需再要移动 - 效率低、费时【js在做垃圾回收时js本身是停顿的】 解决办法可以是标记清除是断续的,清除一个之后执行js,再进行下一个清除,再执行...
优点
相对于引用计数算法来说:解决对象循环引用的不能回收问题。
计数清除
- 当某
一个对象的引用关系发生改变时,引用计数器就会自动的修改这个对象所对应的引用数值,引用数值为0的时候开始工作,将当前的对象空间回收
优点
发现计数为0即回收,减少卡顿时间
缺点
- 无法回收循环引用的对象【可能会出现内存泄漏】
- 时间开销大【时刻监控当前引用数值是否修改,修改需要时间】
新生代:
在新生代当中,V8将内存分为两个相等的空间,分别为From空间和To空间。当From空间被占满的时候,V8会将Form空间中存活对象复制到To空间,并且将Form空间进行清空,然后将From空间和To空间交换,这样就完成了一次垃圾回收。
注:新生代中没有被清除的碎片最后会放到老生代进行清除
TS
语法
let 变量:类型=值
function fn(参数:类型,参数:类型):类型{}
数据类型
-
字面量:
-
let a:10;【将a声明为数字类型,并且确定是10,后续不能更改a=11】 -
let b:"male"|true【`联合类型`:表示字符串“male”或者是布尔“true”】
-
-
any:
- 表示任意类型,相当于对ts关闭了类型检测【显式】
- let a;声明变量不指定类型,也相当于是any【隐式】
-
unknown:
let a:any; let b:string; b=a【相当于把any类型赋给b了,自己不安全还霍霍了别人】- unknown
相对安全,不能把自己赋值给别人 - 可以用
as做类型断言,b=a as string;就不会报错了
类型断言语法:
<类型>变量|变量 as 类型
- unknown
-
viod:
- 表示为空,以函数为例表示没有返回值【表示return null|return undefined】
-
never:
- 表示永远不会返回结果【throw error,立即结束,函数不返回】
-
object&array
-
tuple:
- 固定长度的数组
let a:[number,string,........]按元素顺序声明类型
- 固定长度的数组
-
enum:
enum Gender{male=0;female=1} let a:{name:string,gender:Gerder} i={ name :"李" gender:Gender.female//1 } -
类型别名
类型别名可以简化类型的使用,不能重复声明
type myType=1|2|3|4|5;//给类型取个别名
let a:myType;//直接引用别名就相当于声明类型了
let b:myType;
类
基本写法:
-
直接定义的属性是实例属性,需要通过new出来的实例去访问
-
加上
static关键字的属性是类属性,需要通过类本身去访问 -
【可读,可写,加上
readonly就不能改了】
class Person{
name:string="li"
static age:number=3
constructor(height:number){//每次创建实例时都会调用这个构造函数,通过不同实例访问传参添加属性
this.height=height
}
}
const per=new Person()
console.log(per.name,Person.age)
const per1=new Person(180)
继承:
class Person{
name:string
age:number
constructor(height:number){
this.height=height
}
sayHi(){
console.log("Hi~~~~")
}
}
class Worker extends Person{
//1.继承之后添加方法
doIt(){
console.log(`${this.height}完成项目一`)
}
//2.只在子类中修改方法【方法的重写,也是覆盖】
sayHi(){
console.log("打工人/(ㄒoㄒ)/~~")
}
//3.添加属性
gender:string
constructor(height:number,gender:string){//添加属性后为了让实例访问到,必须重写构造函数
super(height)//必须把父类的构造函数通过super继承过来
this.gender=gender
}
}
const work1=new Worker(158)
work1.doIt()//158完成项目一
work1.sayHi()//打工人打工人/(ㄒoㄒ)/~~
const work2=new Worker(168,"male")
console.log(work2)//Worker {name: undefined, age: undefined, height: 168, gender: 'male'}
抽象类:
-
当不希望父类被用来创建实例时,添加
abstract,称作抽象类 -
抽象类里面可以添加抽象方法,子类
必须对抽象方法进行重写
abstract class Pets{
name:string;
age:number;
constructor(name:string,age:number){
this.name=name;
this.age=age ;
};
//抽象类中可以添加抽象方法,没有方法体
abstract sayhello():void;//子类必须对抽象方法进行重写
}
属性的封装:
用属性修饰符来设置属性:
public:可以在任意位置访问修改private:只能在类内部进行访问修改,若想修改可以通过get、set方法对属性进行设置;继承的子类也不能访问protect:【折中】只能在当前类和当前类的子类中使用,不能通过实例访问
接口
接口用来定义一个类结构,说明一个类里面应该包含哪些属性和方法;可以当作
类型声明去使用
interface myInterface{
name:string;
age:number;
}
const obj:myInterface={
name:"sss",
age:111
}
interface myInterface{//可以重复声明,实现接口时需满足并集
gender:string
}
- 接口中所有的属性都不能有实际的值,只定义对象结构,不考虑实际值,里面所有方法都必须是抽象方法
interface myInter{
name:string;
sayHello():void;
}
class Myclass implements myInter{
name:string
constructor(name:string){
this.name=name
}
sayHello(){
console.log("hello~~~")
}
}
泛型
在定义函数或是类时,如果遇到
类型不明确就可以使用泛型。优点是比any更安全,因为any≠any
基础用法:
//一:基础使用
function fn<T>(a:T):T{
return a
}
fn(a:10)//1.ts对类型进行检查,调用时推断为number
fn<string>(a:"li")//2.调用时指定类型
//二:可以同时指定多个
function func<T,K>(a:T,b:K):T{}
//三:使用接口
interface Inter{
length:number
}
function fun<T extends Inter>(a:T):number{
return a.length
}
fun(a:"hello")//传进来的参数必须有接口的length属性