ES6新特性
- let,const
- 模板字符串:反引号
- 解构赋值
- 箭头函数,函数参数默认值
- 扩展运算符(...)
- forEach,for...of,for...in
- 数组方法:map,reduce,includes
- promise proxy
- async
- class
- 模块化
- map集合和set集合
防抖和节流应用场景
防抖:防止抖动,避免把一次事件误认为多次。登录按钮、发短信按钮避免用户点击太快导致发送多次请求。文本编辑器实时保存、监听浏览器窗口大小时、input框实时搜索。重点:触发则清空定时器clearTimeout(timer)
节流:控制事件发生的频率。控制事件1s发生一次。例如scroll事件,每个1秒计算一次位置信息。浏览器播放事件,每个1秒计算一次进度信息。重点:开关锁timer=null
new关键字
1.当系统检测到new关键字的时候就会在堆中开辟一块内存
2.内存中是个this对象
3.执行构造函数的函数体
4.将this对象的地址赋给我们定义的变量。
const obj1 = new student(arg)
this.$nextTick()的用法
this.$nextTick 等到下次DOM更新之后才执行回调。在修改数据之后立即使用它,然后等待DOM更新。
具体demo
进程和线程
进程:系统进行资源分配和调度的基本单位,比如微信qq就是一个进程。线程是操作系统能够进行运算调度的最小单位。
解构
解构原理:把存放在堆中的数据取出存到栈中,提高效率。
变量提升
var才有变量提升,let和const没有。
js引擎会预解析代码,遇到var声明的变量,会将声明语句提前,然后再重新执行代码。所以先用再声明会是undefined,而不会报错。
什么是回调地狱,如何解决?
回调地狱就是为了实现代码顺序执行的一种操作,它会让这个代码的可读性非常差,不好维护。
那么我们可以Promise来解决这个问题,Promise是一种异步编程的解决方案。
1.Promise构造函数接收一个函数作为参数,我们需要处理的异步任务就卸载该函数体内,该函数的两个参数是resolve,reject。异步任务执行成功时调用resolve函数返回结果,反之调用reject。
2.Promise对象的then方法用来接收处理成功时响应的数据,catch方法用来接收处理失败时相应的数据。
3.Promise的链式编程可以保证代码的执行顺序,前提是每一次在than做完处理后,一定要return一个Promise对象,这样才能在下一次then时接收到数据。
async/await
还有另外一种异步编程的解决方案就是async await,用法就是如果一个函数前面写了async,就表明这个函数是一个异步,不会阻塞后面函数的执行。然后如果你去打印这个函数的返回值时,其实是一个Promise对象。所以我们可以在这个函数后面使用.then,.catch的方法。然后await关键字只能在async定义的函数中使用,await后面一般是跟一个Promise实例对象,并且可以拿到这个实例中resolve的数据。然后必须等await后面这一步成功之后才会继续走下面的代码,这样就保证了代码的执行顺序。
移动端适配
1.视口适配:通过meta标签设置name属性为viewport
2.媒体查询适配:当屏幕宽度满足什么条件时使用什么样式
3.使用js来适配:获取屏幕的宽度然后修改样式
4.Rem适配
This指向
this指向:指向调用者,默认是指向window,但是箭头函数的this是外层上下文的this
微任务和宏任务
Js是单线程的,如果遇到异步的任务会交给浏览器处理
主线程要执行的代码=宏任务
定时器/延时器=宏任务
只有上一个宏任务执行完才会执行下一个宏任务
微任务就是promise .then .catch需要执行的内容
在事件循环队列中,微任务会插队
js用什么方式传参?
简单数据类型值传递,复杂数据类型引用传递
引用传递时重新赋值会断开引用关联
深拷贝和浅拷贝
1.浅拷贝:基本数据类型时是值传递,开了新的内存;复合数据类型时是引用传递,没有开新的内存。
2.深拷贝是再开一个内存,然后整个拷贝过去。
实现深拷贝
1. 简单版:
const newObj = JSON.parse(JSON.stringify(oldObj));
闭包
闭包其实就是我们外部可以调用到函数内部的变量,因为一般外部是不能访问到函数内的变量,但是我们可以通过将函数内的变量return出去给外部调用。
有时候我们想实现数据私有的话就可以使用闭包,如果我们定义全局变量的话容易被污染,可以把变量定义在函数内部,然后定义get方法将变量return出去,这样外部只能访问而不能修改。不过这样也导致了我们的变量一直保存在内存中,如果是一些无用变量的话就会浪费我们的内存。
1.优点:可以实现数据私有,外部可以调用内部的变量,但不能改变,防止全局污染。将变量保存在内存中不被释放,随时调用。
2.缺点:函数运行结束后不能释放内存,消耗内存。
3.闭包解决方法:函数执行完后设置函数=null。
闭包小案例:
function outer(){
let local='变量';
return function(){
console.log(local)
}
}
const fn=outer()
fn()
//闭包导致内存无法释放
//解决方法:null释放内存
fn=null
js垃圾回收机制
js中内存的分配和回收都是自动完成的,内存不使用的时候就会被垃圾回收自动回收。
垃圾回收算法:标记清除:从全局出发,不能被访问的变量就视为垃圾,进行回收。
你对js作用域链的理解?
作用域的话有全局作用域和函数作用域,当你在函数内访问一个变量的时候,会首先在自己的作用域找,如果找不到,就会往外层作用域找,直到全局。
官方:js全局有全局可执行上下文,函数调用时有函数的可执行上下文,会进入js调用栈。
每个可执行上下文都有着对外部上下文词法作用域的引用,内->外->再外,这样就形成了作用域链。
原型链的理解(构造函数+实例+原型)
为什么要在原型上添加方法?
如果一个构造函数里面有很多通用的方法,当我们new多个实例时,虽然方法都是一样,但是浪费内存。
所以如果把通用的方法放到原型上,那么每个实例都可以通过_proto_访问到。
继承
继承:就是继承一些属性和方法
比如有一个构造函数的原型有很多属性和方法,我没有,我就可以去继承过来。
我定义一个人类构造函数,有名字和年龄属性,那么我再定义一个学生构造函数,也有自己的名字和年龄属性,我再定义一个老师构造函数,也有名字和年龄属性,这样就会很麻烦。
我们可以让学生和老师去继承人类的通用属性和方法,然后自己再添加独有的属性和方法。
怎么继承?
1.原型链继承:通过改造原型链来继承
缺点:只能继承方法,属性的构造过程没有得到复用,比如this.age=age这句代码没有继承。
2. 组合式继承:两种技术的结合,原型链技术和借用构造函数(call)
ES6-class类 实现继承
判断是否为数组,不能用typeof
typeof只能判断基本数据类型。
console.log(typeof []) //输出为Object,因为万物皆对象
判断方法1:使用toString
Object.prototype.toString.call([1,2,3])) //输出:[object Array]
判断方法2:使用es6新增的Array.isArray()
isArray([1,2,3]) //true
事件循环队列
js是单线程的,遇到异步的任务会丢给浏览器执行,浏览器是多线程的。
async function fn(){
console.log(111)
}
fn()
console.log(222)
输出结果:111 222
async表示这个函数是异步的,如果没有await等于没写
async function(){
console.log(333)
const res=await 1
console.log(res)
}
fn()
console.log(222)
输出结果:333 222 1
await开始往下的内容,可以理解为写在.then的内容
async function fn(){
console.log('嘿嘿')
const res = await fn2()
console.log(res)
}
async function fn2(){
console.log('gaga')
}
fn()
console.log(222)
输出结果:嘿嘿 gaga 222 undefined
javascript的基本数据类型
undefined,null,number,string,boolean,以及es6新增的symbol
js和jquery获取标签自定义属性的方法分别是什么?
- js可以用getAttribute(),setAttribute()和dataset()获取和设置自定义属性
- jquery可以用attr()和data()方法进行获取
防抖和节流
防抖:触发事件时开始计时n秒后执行回调,当n秒内事件再次被触发的话,就重新计时。
防抖小案例:
let timer=null
function fangdou(){
if(timer){
clearTimeout(timer)
timer=null
}
timer=setTimeout(()=>{
console.log(123)
},500)
}
$('input').keydown(()=>{
fangdou()
})
节流:在一定时间内,多次触发事件只执行一次回调。
节流小案例:
function(){
let timer=null
$(document).mousemove(e=>{
if(timer)return
timer=setTimeout(()=>{
console.log(e)
timer=null
},50)
})
}
数组去重
使用indexOf()==-1,includes(),set集合:Array.form(new Set(arr))