题目总结
JS笔记
1.什么是闭包
- 简单理解就是函数中嵌套函数。我们都知道局部变量我们是无法访问的,但是通过闭包可以做到。
// 正常访问
var lan = 'zh';
function hello(){
var name = '未来';
}
console.log(name)//很明显'undefined'
// 换成闭包
function hello(){
var name = '未来';
function demo(){
console.log(name)//打印:未来
}
}
2.如何理解原型链
- 每个函数都拥有一个prototype属性,每个函数实例对象都拥有一个__proto__属性,
而这个属性指向了函数的prototype,当我们访问实例对象的属性或者方法时,会先从自身构造函数中查找
,如果没有就通过__proto__去原型中查找,这个查找的过程我们称之为原型链。(跟作用域链有点像) - 我们可以看到cat实例对象__proto__指向了Animal,当cat没有age的时候,会通过__proto__到原型上查找,
如果原型上依然没有,会继续向Object上查找
3.如何理解作用域链
- 前沿知识:js代码执行前会创建上下文环境,这个上下文环境包含了变量、作用域链和this.
- 简单理解就是从当前环境向父级一层一层查找变量的过程称之为作用域链。
var name = '未来';
function hello(){
console.log(name);
}
4.继承有哪些方法
- 原型继承
- 构造继承
- 实例继承
- call/apply继承(组合继承)
- ES6 使用class extends继承
5.什么是深/浅拷贝,有哪些实现方式
JS数据类型分别基本数据类型和引用数据类型,基本数据类型保存的是值,引用类型保存的是引用地址(this指针)。
浅拷贝共用一个引用地址,深拷贝会创建新的内存地址。
- 浅拷贝方法
直接对象复制
Object.assign
- 深拷贝
JSON.stringify转为字符串再JSON.parse
深度递归遍历
6.如何准确判断一个对象是数组
- 面试官希望的答案:Object.prototype.toString.call([]) 返回 “[object Array]”
扩展答案
[].slice (能力判断 )
[] instanceof Array(类型判断)
[].proto ===Array.prototype
Array.isArray([]) 存在兼容问题
- 数组也是引用类型,通过typeof依然返回object
7.数组有哪些常用方法
这个非常多,说起来也很快,我主要考察你会多少,另外也为了引出下一个问题,slice和splice区别
push 末尾添加
pop 末尾删除
shift 首部删除
unshift 首部添加
concat 数组合并
join 数组元素 通过连接符 连接
reverse 数组反转
sort 数组排序
map/forEach/filter/indexOf/includes/slice/splice
slice表示截取,slice(start,end)不改变原数组,返回新数组。
splice表示删除,splice(start,length,item),会改变原数组,从某个位置开始删除多个元素,并可以插入新的元素。
8.call/apply/bind作用和区别
- 他们都可以改变函数的作用域。
- call/apply可以直接执行该函数,而bind不会立刻执行
- call/apply作用类似,都可以改变指针和执行函数,区别在于传参不同,call需要单个传参,apply通过数组传参
9.DOM节点创建和修改有哪些常用API
创建节点
- createElement
- createTextNode
- createDocumentFragment(临时节点)
修改节点 - appendChild parent.appendChild(child)
- insertBefore parentNode.insertBefore(newNode,refNode);
- removeChild parent.removeChild(node)
- replaceChild
10.谈一下EventLoop
这其中大家需要了解几个概念:调用栈、同步/异步任务、宏任务/微任务
JavaScript本身是单线程,也就是同一时刻只能干一件事,JS任务包含了同步任务和异步任务,
遇到执行函数会将其放入调用栈(先进后出)中,遇到setTimeout/setInterval等异步任务时,
会把它放入到消息队列中,等主线程的任务执行完成以后,再回过头执行消息队列中的异步任务,
如果异步任务中仍然有异步任务,会继续放入消息队列,以此类推,便形成了一个事件循环。
异步任务:
- setTimeout
- setInterval
异步任务又分为宏任务和微任务,promise就属于微任务.
11.节流和防抖
11.1 节流(通过设置perTime与nowTime)
节流技术是用于设定在固定事件内,执行特定的功能代码,如果同一单位事件内某事件被多次触发,那么只有一次生效
(节流可以用在scroll函数的事件监听上,通过事件节流来降低事件调用的频率)
节流的实现
function limtfun(fun, wait) {
var perTime = 0;
return function () {
var nowTime = new Date()
if (nowTime - perTime > wait) {
fun.call(this)
perTime = nowTime//由于闭包的原因,这里的nowTime不会被清空
}
}
}
11.2 防抖(通过定时器)
- 在时间触发n秒后再执行回调,如果这n秒内事件又被触发,则重新计时
- 比如在搜索功能时,用户输入关键字搜索,不用每次输入都发送请求显示数据,只有等待用户停止输入后等待一定的时间(确保用户不再输入),再执行特定功能的代码。
所用的技术是定时器,和闭包技术
防抖的实现
function debounce(fun, wait) {
let timer = null;
//所以下面的匿名函数适应的函数外部的变量,这里是闭包的作用
return function () {
//清空计时器是为了当事件又被触发时,重新计时
clearInterval(timer)
timer = setInterval(() => {
fun.apply(this)
}, wait)
}
}
var result = debounce(fun1, 1000)
result()
12.node的事件环的理解和实现
node代码在执行时,执行是在 栈中执行的,先执行微任务,在执行宏任务,一旦执行到某一个阶段,会等这个阶段的所有代码执行完毕后,再切换到另一个阶段
- 我们写的js代码会交由V8引擎进行处理
- 代码中可能会调用NodeApi,node会交由libuv处理
- libuv通过阻塞I/O和多线程实现异步I/O
- 然后通过事件驱动的方式,将结果放到事件队列中,最终交给我们的应用。
13.pm2和pm3的区别
PM2 (github上的源码)是开源的基于Nodejs的进程管理器,包括守护进程,监控,日志的一整套完整的功能,基本是Nodejs应用程序不二的守护进程选择,事实上它并不仅仅可以启动Nodejs的程序,只要是一般的脚本的程序它同样可以胜任。