块级作用域
变量提升
最佳实践:不使用var ,默认使用const ,明确会改变的使用let。
const arr = [1,2,3]
const [a,b] = arr;
const [,,c] = arr;
使用…方式解构
const [a,...rest] = arr;
//默认值
const [a,b,c,d = 12] = arr
const obj = {
name:'zs',
age:18
}
const {
name} = obj;
// 重命名
const {
name:rename} = obj;
let str = `
i am
${
name}
`
// 带标签的模板字符串
const str = console.log`hello world`
… 操作符
function fn(...args){}
const arr = [1,2,3];
console.log(...arr)
不会改变this的指向。
箭头函数不适用:
const obj = {
foo:123,
method1(){
console.log('1')
},
//计算属性名
[Math.random](){
}
}
const source1 = {
a:123,
b:23
}
const target = {
a:123,
c:23
}
const res = Object.assign(target,source1)
Object.defineProperty – ES5监听数据变更的API vue2的底层实现
proxy – ES6 vue3的底层实现
const person = {
name:'ss',
age:19
}
const personProxy = new Proxy(person,{
get(target,key){
console.log(target,key)
return 100;
},
set(target,key,value){
console.log(target,key,value)
}
})
console.log(personProxy.name)
personProxy.sex = '女'
proxy的优势:
const person = {
name:'ss',
age:19
}
const personProxy = new Proxy(person,{
deleteProperty(target,property){
console.log('delete')
}
})
delete personProxy.age
const list = []
const listProxy = new Proxy(list,{
set(target,property,value){
console.log(target,property,value)
target[property] = value;
return true//表示设置成功
}
})
listProxy.push(10)
统一的对象操作API
静态类
内部封装了一系列对对象的底层操作 。
const person = {
name:'ss',
age:19
}
const personProxy = new Proxy(person,{
get(target,key){
// ... 自定义逻辑
return Reflect.get(target,key)
},
set(target,key,value){
console.log(target,key,value)
}
})
console.log(personProxy.name)
personProxy.sex = '女'
Reflect.has
Reflect.deleteProperty
Reflect.ownkeys
异步编程解决方案
// es5
function Person(name) {
this.name = name
}
Person.prototype.say = function(){
}
// es6
class Person{
constructor(name){
this.name = name
}
say(){
}
}
const person = new Person('zhangsan');
class Person{
constructor(name){
this.name = name
}
// 实例方法
say(){
}
// 静态方法
static create(name){
return new Person(name)
}
}
class Person{
constructor(name){
this.name = name
}
say(){
console.log('父say')
}
}
class Student extends Person{
constructor(name,number){
super(name)
this.number = number
}
hello(){
super.say();
console.log('hello')
}
}
let stu = new Student('zhaosi',12342);
stu.hello();
Set 不允许重复
const set = new Set();
set.add(1).add(2).add(3)
// 遍历
set.forEach(()=>{
})
for(let i of set){
}
set.size
set.has()
set.delete()
set.clear()
const arr = [1,2,3,1,4,2]
const set1 = new Set(arr)
Array.from(set1)
const arr1 = [...set1]
Map
类似对象,
const obj = {
}
obj[true] = 'value'
obj[123] = 'value'
obj[{
a:1}] = 'value'
Object.keys(obj)
const m = new Map()
const tom = {
name:'tom'}
m.set(tom,99)
m.has()
m.delete()
m.clear()
m.forEach(()=>{
})
const a = Symbol()
console.log(a)
const obj = {
}
obj[Symbol('a')] = 123;
obj[Symbol('b')] = 445;
console.log(obj[Symbol('a')])
const a = Symbol.for('foo')
const b = Symbol.for('foo')
console.log(a===b)
const obj1 = {
[Symbol.toStringTag]:'XObject'
}
console.log(obj1.toString()) // [object XObject]
私有属性
const arr = [2,324,12,324,2,234]
for(let i of arr){
console.log(i)
if(i>188){
break
}
}
// arr.forEach() //无法中断循环
// arr.some()
// arr.every()
// 遍历set、map
可迭代接口 Iterable
实现Iterable接口,是使用for…of的前提
const arr = [1,23,321,421]
const iterator = arr[Symbol.iterator]()
iterator.next()
实现可迭代接口
const obj= {
store:['foo','bar','baz'],
[Symbol.iterator]:function(){
let index = 0;
const self = this;
return {
next:function(){
const res = {
value:self.store[index],
done:index>=self.store.length
}
index ++
return res;
}
}
}
}
for(let item of obj){
console.log(item)
}
迭代器模式
const todo = {
life:['s','d'],
learn:['e','w2'],
work:['dfa'],
each:function(cb){
const all = [].concat(this.life,this.learn,this.work)
for(const item of all){
cb(item)
}
},
[Symbol.iterator]:function(){
const all = [...this.life,...this.learn,...this.work]
let index = 0;
return {
next:function(){
return {
value:all[index],
done:index++>=all.length
}
}
}
}
}
//for(let item of to.life){}
//for(let item of to.learn){}
//for(let item of to.work){}
todo.each(function(item){
console.log(item)
})
for(let item of todo){
console.log(item)
}
避免回调嵌套
function * foo(){
console.log('zcc')
return 100
}
const res = foo();
console.log(res)
res.next()
// 配合 yield
function * boo(){
console.log('111')
yield 100
console.log('222')
yield 200
console.log('333')
yield 300
}
const gen = boo();
gen.next()
生成器应用
// 案例 : 发号器
function * createID(){
let id = 1;
while(true){
yield id++
}
}
const id = createID();
id.next()
// 实现iterator方法
const todo = {
life:['s','d'],
learn:['e','w2'],
work:['dfa'],
[Symbol.iterator]:function * (){
const all = [...this.life,...this.learn,...this.work]
for(let item of all){
console.log(item)
}
}
}
for(let item of todo){
console.log(item)
}
模块化
ES2016
ES2017
function foo(arg1,arg2,){
}
解决JS类型系统问题
强类型 VS 弱类型 (类型安全)
强类型有更强的类型约束。
强类型不允许隐式类型转换。
弱类型的问题
const obj = {
}
obj[123] = 456
obj[123] // undefined
1、JS的超集
yarn add typescript --dev
tsc .\01-getting-start.ts
3、配置文件 tsconfig.json
tsc --init
4、 原始类型
const a:string = 'foo'
const b: number = 12;
const c:boolean = false;
// 注意:严格模式 不能为空的
const d:void = undefined
const e:null = null
const f:undefined = undefined
// 报错 const g:symbol = Symbol()
// 解决:1、(tsconfig.json)target-->es2015
// 2、 (tsconfig.json) "lib": ['ES2015','DOM'],
// const g:symbol = Symbol()
// Promise
标准库-- 就是内置对象所对应的说明
5、 TS中文错误消息
tsc --locale zh-Ch
或者 vscode中设置
6、类型
// Object 泛指所有非原始类型
const foo :object = function(){
}
const obj :{
foo:number,bar:string} = {
foo:123,bar:'string'}
const arr1 : Array<number> = [1,2,3]
const arr2:number[] = [1,2,3]
function sum(...args:number[]) {
return args.reduce((pre,cur)=>pre+cur,0)
}
sum(1,2,3)
// 元组类型
const tuple :[number,string] = [12,'str']
// const age = tuple[0]
const [age,name01] = tuple
const post = {
title:'hello ts',
content:'ts is a typed',
status:3
}
// const PostStatus = {
// Draft:0,
// Unpublished:1
// }
enum PostStatus{
Draft = 0,
Unpublished = 1,
Published = 2
}
//常量枚举
const enum PostStatus1{
}
// 函数
// 可选参数 ? 或 参数默认值
function func1(a:number,b?:number):string {
return 'str'
}
func1(1,2)
// 任意参数 rest
const func2 = (a:number):string=>{
return 'abc'
}
隐式类型推断
类型断言
// as 关键字
const num1 = res as number; //(推荐)
//或
const num2 = <number>res; // 会和JSX标签冲突
7、 接口
// function printPost(post){
// console.log(post.title);
// console.log(post.content);
// }
// 接口
interface Post{
title:string
content:string
subtitle?:string // 可选成员
readonly summary:string // 只读成员
}
function printPost(post:Post){
console.log(post.title);
console.log(post.content);
}
printPost({
title:'标题',
content:'这是一段文字',
summary:'摘要'
})
// 任意成员
interface Cache{
[prop:string]:string
}
8、类
// TS增强了class的特性
class Person {
name:string
age:number
protected gendar:boolean
constructor(name:string,age:number){
this.name = name
this.age =age
this.gendar = true
}
sayHi(msg:string):void{
}
}
// 类的访问修饰符 private(不能外部访问)
// public(默认)
// protected(不能外部访问,子类可访问)
class Student extends Person{
constructor(name:string,age:number){
super(name,age)
console.log(this.gendar);
}
static create(name:string,age:number){
return new Student(name,age)
}
}
const tom = new Person('tom',10)
console.log(tom.name);
const jack = new Student('jack',13)
// 只读属性 - readonly
类和接口
//用接口抽象类的共同属性
interface Eat {
eat(food:string):void
}
interface Run{
run(distance:number) :void
}
class Person1 implements Eat,Run{
eat(food:string):void{
}
run(distance:number):void{
}
}
class Animals implements Eat,Run{
eat(food:string):void{
}
run(distance:number):void{
}
}
抽象类:约束子类必须有某些成员,只能被继承;
子类必须实现父类的抽象方法。
abstract class Animals {
eat(food:string):void{
}
abstract run(distance:number):void
}
9、泛型
// 泛型
function createNumberArray(length:number,value:number):number[] {
const arr = new Array<number>(length).fill(value);
return arr
}
// function createNumberString(length:number,a:string):string[] {
// const arr = new Array(length).fill(a);
// return arr
// }
// function createArray(length:number,value:T):T[] {
// const arr = new Array(length).fill(value);
// return arr
// }
10、类型声明
1、 JS的类型检查器
通过类型注解的方式,检查类型。
function sum(a:number,b:number){
return a + b
}
通过babel去除注解代码。
2、 使用
yarn add flow-bin --dev // 安装
yarn flow init //初始化配置文件
yarn flow
yarn flow stop //停止命令
3、 编译移除注解
yarn add flow-remove-types --dev // 移除
yarn flow-remove-types . -d dist
// 或者 通过babel方式移除
yarn add @babel/core @babel/cli @babel/preset-flow --dev
yarn babel part01/module02/flow -d dist // 命令
通过babel的 方式 要配置.babelrc文件,配置如下:
{
"presets":["@babel/preset-flow"]
}
4、开发工具插件
Flow Language Support ------------ VScode插件
5、 flow类型
/**
* @flow
*/
const a : string= '12'
const b :number = NaN // Infinity
const c:boolean = true
const d : null = null
const e:void = undefined
const f:symbol = Symbol()
/**
* @flow
*/
const arr:Array<number> = [12,3,4]
const arr1 :number[] = [1,2,3]
// 固定长度的数组 --- 元组
const foo:[string,number] = ['s',12]
/**
* @flow
*/
const obj:{
foo:string,
bar:number
} = {
foo:'s',
bar:125
}
// 可选属性
const obj1:{
foo:string,
bar?:number
} = {
foo:'s'
}
const obj3 :{
[string]:string}= {
}
obj3.key ='value'
obj3.key2 = 'value2'
/**
* @flow
*/
function fn(a:number,b:number) :number{
return a+b
}
function foo(cb:(string,number)=>void) {
cb('str',100)
}
/**
* @flow
*/
// 字面量类型
const a :'foo' = 'foo';
// 联合类型
const type:'success'|'warning'|'danger' = 'success'
const b :string | number = 100;
type StrORNum = string|number;
const c : StrORNum = 123;
// maybe类型 可以为空 ?
const gender : ?number = null
// @flow
// mixed 任意类型 --- 强类型
function passMixed(value:mixed){
if(typeof value === 'string'){
value.substr(1)
}
}
passMixed('2ss')
passMixed(20)
// any --- 弱类型
function passMixe2(value:any){
}
/**
* any 和 mixed区别
*
* any是弱类型的,mixed是强类型的。
* 尽量不要使用any
*
*/
6、 flow运行环境API
// @flow
const ele:HTMLElement | null = document.getElementById('app')
1、内存管理
申请、使用、释放空间。
2、垃圾回收 、常见GC算法
let obj = {
name:'xx'}
let ali = obj;
obj = null;
// 可达对象
function objGroup(obj1,obj2) {
obj1.next = obj2;
obj2.pre = obj1;
return {
o1:obj1,
o2:obj2
}
}
let obj00 = objGroup({
name:'222'},{
name:'333'})
[思想] 设置引用数,判断当前引用数是否为0
引用计数器
引用关系改变时修改引用数字
引用数字为0 回收
[优点] 发现垃圾时立即回收
[优点] 最大限度减少程序暂停
[缺点] 无法回收循环引用的对象循环引用
[缺点] 时间开销大
// 引用计数
const user1 = {
age:11}
const user2 = {
age:22}
const user3 = {
age:33}
const nameList = [user1.age,user2.age,user3.age]
function fn(){
const num = 1
const num1 = 2
}
fn();//调用后 num num2 引用为0 回收
// 循环引用
function fn() {
const obj1 = {
}
const obj2 = {
}
obj1.name = obj2
obj2.name = obj1;
return 'x'
}
fn()
3、V8的垃圾回收
4、performance工具
5、代码优化
如何精准测试JS性能?
jsperf使用流程
慎用全局变量
缓存全局变量
通过原型对象添加附加方法
避开闭包陷阱
避免属性访问方法使用
选择最优的循环方法
直接量替换new Object
var a = [1,2,3]// 推荐
var a1 = new Array(3)
a1[0] = 1;
a1[1] = 2;
a1[2] = 3;