1. 深拷贝手写
代码
1判断值类型和引用类型typeof2判断对象数组instanceof3遍历 +递归hasOwnProperty + 递归
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj = {}) {
if (typeof obj !== 'object' || obj == null) {
// obj 是 null ,或者不是对象和数组,直接返回
return obj
}
// 初始化返回结果
let result
if (obj instanceof Array) {
//判断 传入的是数组还是对象
result = []
} else {
result = {}
}
for (let key in obj) {
// 保证 key 不是原型的属性
if (obj.hasOwnProperty(key)) {
//每一个key 看看他是不是原型的属性,就是别人赋值给他的
// 递归调用!!!
result[key] = deepClone(obj[key])
}
}
// 返回结果
return result
}
ps:只有在判断一个对象的某个属性是否存在的时候采用 ==
2. 原型原型链
题目
- 如何准确判断一个变量是不是数组?
- 手写一个简单的jQuery,考虑插件和扩展性
- class 的原型本质
知识点
- class 和继承
- 类型判断 instanceof
- 原型和原型链
- class 可以理解为模板,可以通过模板来构建(
construction) 属性或者方法 - 代码演示
class Student {
constructor(name,number) {
this.name =name
this.number =number
}
sayHi(){
console.log(
`姓名${this.name} , 学号 ${this.number}`
)
}
}
const xialuo = new Student('name',100)
console.log(xialuo.name)
console.log(xialuo.number)
xialuo.sayHi()
- 继承 使用
extends来做的;通过super来执行父类的构造函数
// 父类
class People{
constructor(name) {
this.name = name
}
eat(){
console.log(`${this.name} 吃饭`)
}
}
// 子类
class Student extends People{
constructor(name,number) {
super(name)
this.number= number
}
sayHi(){
console.log(`姓名${this.name} , 学号 ${this.number}`)
}
}
//实例
const xialuo = new Student('夏洛',100)
console.log(xialuo.name)
console.log(xialuo.number)
xialuo.sayHi()
xialuo.eat()
3. 作用域和闭包
闭包面试题(两次打印的结果分别是什么?)
两次打印的结果都是 100
解析
闭包:自由变量的查找,是在函数定义的地方向上级作用域查找,而不是在函数调用执行的地方!!!
4, this 的多种场景
重点
(this 的值取决于函数执行的时候确定的,不是在函数定义的时候!!!!!)
场景1:直接调用,指向window
场景2:call改变this 的指向
场景3:bind
call 是一调用就执行了,bind是返回一个新的函数!
调用新的函数
场景4:普通setTimeout 的this
场景5,箭头函数的this
场景5: class 里面的this
手写 bind
5.异步应用场景
- 网络请求,如ajax图片加载
- 定时任务,如setTimeout
手写Promise加载一张图片
const url ='https://xxx'
function loadImg(src){
return new Promise(
(resolve,reject)=>{
const img =document.creatElement('img)
img.ondland()=>{
resolve(img)
}
img.onerror()=>{
reject(new Error('图片加载错误))
}
img.src = src
})
}
//调用loadImg 方法
loadImg(url).then(img=>{
console.log(img.width)
return img
}.then(img={
console.log(img.width)
}))
6.JS异步-进阶
请描述event-lppo的机制?
DMO 事件和 event-loop
Promise 的3种状态!
场景题:Promise then 和catch的连接?
resolve 状态下只会执行 then,reject 状态只会执行 catch then 和 catch 执行没有抛出错误,都返回的是 resolve 状态;否则返回的是rejected 状态
第一题:13打印 第二题:123打印 第三题:12打印
异步的本质
场景题:async 和 await
执行 async 后面的函数,相当于 return Promise resolve(res) 一个promise await 后面的函数相当于 Promise 的then ;有三种方式
- await Promise.resolve(200)
- await 200
- await fn()1 // async function fn1(){return Promise.resolve(200)}
a 是一个Promise对象,b 是100 当await后面接一个Promise对象的时候,相当于是一个then
start a,100 b,200 当遇到await Promise.reject(300)的时候,因为是rejected 状态的,使用直接就报错了,不会在往下执行了
这个的打印顺序!!!高级 8.11
-
(高级,await 后面的代码全部都视为异步的)
-
(高级,遇到 async 得立刻去执行 async 后面的函数)
场景题:promise 和setTimeout 的顺序
100 400 300 200
场景题:高级程序员 大boss 题目!8.17
fo in 和 for of 的区别!
for of 用于遍历时的异步的场景
async/await 总结
什么是宏任务,什么是微任务?
宏任务 macroTask ; 微任务 microTask
- 什么是 宏 微?
为什么300比200 先打印
- event loop 和 DOM渲染
每一个轮询结束(call stack清空)之后,都会先尝试DOM 渲染;再去触发 Event loop
- 宏 微区别是? 代码演示
宏任务:DOM渲染后触发,如setTimeout
微任务:DOM渲染前触发,如Promise
4. 原因?
当遇到 Promise微任务的时候,会放到微任务的队列里面去,不是像宏任务 setTimerout 的宏任务队列,因为 Promise是ES6规定的,但是AJAX,setTimerout 是浏览器规定的! 那么我们的1234的顺序就变了:
- Call Stack 清空
- 执行当前的微任务(微任务队列)
- 尝试DOM渲染
- Event Loop触发
- 执行宏任务队列
-
总结
- 宏任务,微任务有哪些?微任务触发时机更早。
- 他们和DOM渲染的关系是啥?
- 微任务、宏任务和DOM渲染,在event loop 的过程