文章目录
同步任务和异步任务
同步任务立即执行
异步任务会放到任务队列里等同步任务执行完毕后再执行
回调地狱
多层回调函数的相互嵌套,就形成了回调地狱
缺点:
- 代码耦合性太强,难以维护
- 代码冗余,可读性差
解决办法:
- Promise回调函数异步操作
深拷贝 浅拷贝
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存(分支)。
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是“值”而不是“引用”(不是分支)
我们希望在改变新的数组(对象)的时候,不改变原数组(对象),这时就要使用深拷贝
深拷贝方法:
JSON.parse(JSON.stringify())
- 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
- 手写递归方法,遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝
- 函数库lodash
var _ = require('lodash') var arr=[{a:1,b:2},{c:1,d:2}]; var arr2=_.cloneDeep(arr)
更改this 指向
// 旧写法
var Person = {
name:'张三',
say:function(age=0){
console.log(`my name is ${this.name}, i am ${age} years old`)
}
}
var obj = {name:'李四'}
Person.say() //my name is 张三, i am 0 years old
//bind
Person.say.bind(obj,20)() //my name is 李四, i am 20 years old
Person.say.bind(obj)(30) //my name is 李四, i am 30 years old
//call
Person.say.call(obj,40) //my name is 李四, i am 40 years old
//apply
Person.say.apply(obj,[50]) //my name is 李四, i am 50 years old
局部创建后端项目
全局: npm install express-generator
局部: express --view=ejs <项目名称>
严格模式
严格模式下运行JS,只要函数参数使用默认值、解构赋值、拓展运算符,那么函数内部就不能显示设定为严格模式
正则基础
Obejct
数据类型
- Undefined
- Null
- String
- Number
- Boolean
- Object(包含Array、Function、Date、RegExp、Error)
- Symbol
prototype与__proto__的区别和关系
prototype是在构造函数上的,而__proto__是在对象上的
var let const
var
- 存在变量提升
- 可多次声明,后面的覆盖前面的
- 函数内部用var声明的变量是局部的,函数外是全局的
let
- 无变量提升,let声明之前,该变量不能使用(暂时性死区)
- let存在作用域
- let 在同作用域重复声明会报错
const
- const声明一个只读变量,声明后就不能改变
- const必须初始化
- const不是变量的值不能改变,而是变量指向的地址保存的数据不能改变
- 其他特点与let一样
const声明的好处,一让阅读代码的人知道该变量不可修改,二是防止在修改代码的过程中无意中修改了该变量导致报错,减少bug的产生。
属于异步任务的三种回调函数
- 定时器的回调函数
- 事件(点击)的回调函数
- ajax请求的回调函数
闭包
闭包(closure)是一种函数,他有权访问另一个函数作用域中的变量
闭包是一种现象,指在某作用域中访问另外某作用域中的局部变量
作用:延申了变量的作用范围
简单样例:
function fn(){
let num = 10
return function(){
console.log(num)
}
}
let f = fn()
f() //10,fn中产生闭包
Generator与async await
对象原型 prototype
JS 是基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。
原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链
对象原型解释了为何一个对象会拥有定义在其他对象中的属性和方法。
理解样例
const prototype1 = {};
const object1 = Object.create(prototype1);
console.log(Object.getPrototypeOf(object1) === prototype1);// true
js中==和===区别
== 代表相同, ===代表严格相同
==比较时: 先检查两个操作数数据类型,如果相同, 则进行===比较, 如果不同, 则愿意为你进行一次类型转换, 转换成相同类型后再进行比较
===比较时, 如果类型不同,直接就是false.
观察者模式
当对象间存在一对多关系时,则使用观察者模式,比如当一个对象被修改时,则会自动通知依赖它的对象。
使用场景:目标对象的状态发生改变,所有的观察者对象(依赖对象)都将得到通知,进行操作
优点:观察者和被观察者时抽象耦合的
缺点:如果关联太多,则花费时间也会很多,如果交替依赖则有可能系统崩溃
class Sub{//发生状态变化的对象
constructor(){
this.state = 0
this.observers = []
}
setState(state){
this.state = state
this.notify()
}
getState(){
return this.state
}
attach(observers){//新增观察者
this.observers.push(observers)
}
notify(){//通知观察者
this.observers.forEach(s=>{s.update()})
}
}
class Observers{//观察者对象
constructor(name,sub){
this.name = name
this.sub = sub
this.sub.attach(this)
}
update(){
console.log(`${this.name}观者这更新了:${this.sub.getState()}`);
}
}
let s = new Sub()
let o = new Observers('test', s)
s.setState(3) //test观者这更新了:3
for、for…in、for…of、forEach比较
- for语句是一种先测试的循环语句,即 先检测退出条件,在执行循环体
- for…in是严格的迭代语句,只用于枚举对象中的 非符号键属性
- for…of是严格的迭代语句,用于遍历可迭代对象的 元素值
- for…Eack()方法用于调用 数组 的每个元素,并传递给回调函数
总结:
- forEach()不能直接break终端循环,其他不可以
- for…in可以直接遍历对象,其他不可以(for…of、for需要遍历对象的迭代器,Object.keys())
- for…in遍历的是索引键,for…of遍历的是数组的元素值
Vue有哪些生命周期
- beforeCreate() 在实例创建之间执行,数据未加载状态
- created() 在实例创建、数据加载后,能初始化数据,dom渲染之前执行
- beforeMount() 虚拟dom已创建完成,在数据渲染前最后一次更改数据
- mounted() 页面、数据渲染完成,真实dom挂载完成
- beforeUpadate() 重新渲染之前触发
- updated() 数据已经更改完成,dom 也重新 render 完成,更改数据会陷入死循环
- beforeDestory() 和 destoryed() 前者是销毁前执行(实例仍然完全可用),后者则是销毁后执行
Vue的nextTick有什么用
Vue中异步执行 DOM 更新,所以当DOM1的数据变化后,DOM2需要从 DOM1的 DOM 结构中获取数据或进行操作,会发现数据没有实时更新,这时就需要用 nextTick:this.$nextTick(function(){})