JavaScript
2021-03-24 15:02:30 0 举报
AI智能生成
前端面试_JavaScript
作者其他创作
大纲/内容
JavaScript
JS 基础
变量类型和计算
JS 值类型和引用类型的区别
值类型
深入分析
引用类型
浅拷贝:复制的时候只拷贝内存地址
栈从上往下排列,堆从下往上排列
考虑性能和存储
常见值类型
常见引用类型
手写 JS 深拷贝
typeof 运算符
判断所有值类型
判断函数,能识别引用类型(不能再继续识别)
深拷贝
浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址;深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存。
变量计算 - 类型转换
字符串拼接
== 运算符
只有一个地方用 == :判断是 null 或 undefined 时,其他一律用 ===
if 语句和逻辑运算
truly 变量:!!a === true 的变量falsely 变量:!!a === false 的变量
if 语句,就是判断 truly 变量 和 falsely 变量
逻辑判断
变量类型相关面试题
typeof 能判断哪些类型?
何时使用 ===,何时使用 ==?
值类型和引用类型的区别
手写深拷贝
原型和原型链
如何用 class 实现继承
class
constructor属性方法
继承
extendssuper扩展或重写方法
示例
如何理解 JS 原型(隐式原型和显示原型)
类型判断 - instanceof
通过 instanceof 判断该实例是否是某个父类构建的,返回布尔值
instanceof 用于判断引用类型
Object 是所有 class 的父类,包括 Array
原型
隐式原型:__proto__;显示原型 prototype
原型关系:每个class 都有显示原型 prototype每个实例都有隐式原型 __proto__实例的 __proto__ 指向 class 的 prototype
基于原型的执行规则:获取属性或方法时,先在自身属性或方法找如果找不到,就去 __proto__中找
intanceof 是基于原型链实现的
原型链
原型链:是用来查找引用类型的属性方法的。
当访问一个对象的某个属性时:会先在这个对象本身属性上查找;如果没有找到,则会去它的 __proto__ 隐式原型上查找,即它的构造函数的 prototype;如果还没有找到就会再在构造函数的 prototype 的 __proto__ 中查找,一直往上层查找,直到到 Object.prototype.__proto__ 还没有找到,则返回 undefined (Object.prototype.__proto__ === null)
hasOwnPrototype:检测一个属性是否是对象的自有属性,而不是从原型链继承的
原型相关面试题
如何准确判断一个对象是不是数组?
a instanceof Array
class 的原型本质,怎么理解?
原型和原型链的图示属性和方法的执行规则
手写一个简易的 jQuery,考虑插件和扩展性
作用域和闭包
作用域
变量的合法使用范围
全局作用域:在全局可以使用函数作用域:只能在函数块中使用块级作用域(ES6新增):let,const定义的变量有块级作用域{}内部使用
自由变量
一个变量在当前作用域没有定义,但是被使用了:向上级作用域,一层一层依次寻找,直到找到为止;如果到全局作用域都没找到,则报错:xxx is not defined
闭包
作用域应用的特殊情况,有两种表现:函数作为参数被传递函数作为返回值被返回(总之,函数定义和使用不在一个地方)
函数作为参数
函数作为返回值
闭包就是能够读取其他函数内部变量的函数
所有的自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方!!!
this
this 应用场景
作为普通函数被调用使用 call apply bind 调用作为对象方法被调用在 class 方法中 调用箭头函数
普通函数,call,bind
call,apply,bind 都可以改变 this,不同的是: call 的参数是直接放进去的,参数全都用逗号分隔;apply 的所有参数都必须放在一个数组里面传进去;bind 要返回一个新的函数去执行,call apply 调用则执行。
对象方法
箭头函数
箭头函数里的 this 永远取它上级作用域的 this
this 取什么样的值,是在函数执行的时候确定的,不是在函数定义的时候确定的!!!
作用域相关面试题
this 的不同应用场景,如何取值?
手写 bind 函数
Array.prototype.slice.call(arguments) 能将具有 length 属性的对象转成数组argument 为类数组slice 从已有的数组中返回选定的元素slice 方法可以用来将一个类数组对象/集合转换成一个新数组,只需将该方法绑定到这个对象上。
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值;pop() 方法用于把数组的最后一个元素从其中删,并返回最后一个元素的值。
实际开发中闭包的应用场景,举例说明
闭包隐藏数据,只提供 API
创建 10 个 a 标签,点击的时候弹出对应的序号
注意 let i 写在 for 里,for 里的块级作用域;若写在 for 外面,是全局作用域,for 一次性执行完,点击时 i 均为10
异步
单线程和异步
JS 是单线程语言浏览器和 nodel.js 已经支持 JS 启动进程,如 Web Worker (但只是进程,JS 本质还是单线程)JS 和 DOM 渲染共有同一个线程,因为 JS 可修改 DOM 结构(因此JS 执行过程中,DOM 渲染需要停止)遇到等待(网络请求、定时任务)不能卡住
需要异步来解决单线程等待的问题(callback 回调函数的形式来调用)
异步和同步的区别
JS 是单线程语言,同步会阻塞代码执行,异步不会
异步的应用场景
网络请求,如 ajax、加载图片定时任务,如 setTimeout、setInterval
Promise 的基本使用
callback hell(回调地狱,越陷越深)
Promise 语法
异步相关面试题
同步和异步的区别是什么?
手写 Promise 加载一张图片
前端使用异步的场景有哪些?
setTimeout 笔试题
分别打印 1,3,5,4,1s后打印2
JS 异步进阶
event loop(事件循环/事件轮询)
什么是 event loop?
JS 是单线程运行的异步要基于回调来实现event loop 就是异步回调的实现机制
JS 如何执行?
从前到后,一行一行执行如果某一行执行报错,则停止下面代码的执行先把同步代码执行完,再执行异步
event loop 的执行过程
在 JS 引擎里call stack:调用栈web APIs:在 ES6 规范之外,浏览器定义的event loop:事件轮询callback queue:回调函数队列
同步代码,一行一行放在 call stack 中执行遇到异步,先“记录”下,等待时间(定时,网络请求等)时机到了,就移动到 calllback queue如果 call stack 为空(即同步代码执行完),尝试 DOM 渲染,再触发 event loop轮询查找 callback queue,如有则移动到 call stack 执行继续轮询查找(永动机一样)
DOM 事件 和 event loop 的关系
DOM 事件和异步(setTimeout,ajax等)都是使用回调,基于 event loop 实现;它们的触发时机都是由浏览器控制的,但 DOM 事件不是异步
Promise
Promise 有那三种状态
pedding 过程中resolved 成功rejected 失败
状态的变化
pedding --> resolved 或 pedding --> rejected变化不可逆
状态的表现
pending:不会触发 then 或 catchresolved:会触发后续的 then 回调函数rejected:会触发后续的 catch 回调函数
Promise 的 then 和 catch 如何影响状态的变化
then/catch正常返回 resolved 状态的 Promise(会触发后续的 then 回调函数)里面有报错则返回 rejected 状态的 Promise(会触发后续的 catch 回调函数)
async/await
背景
异步回调 callback hellPromise then catch 链式调用,但还是基于回调函数async/await 是同步语法,彻底消灭回调函数
基本使用
await 必须放在 async 函数中,否则会报错
async/await 和 Promise 的关系
async/await 消灭异步回调,但和 Promise 并不互斥,相辅相成
执行 async 函数,返回的是一个 Promise 对象await 相当于 Promise 的 thentry...catch 可捕获异常,相当于 Promise 的 catch
async/await 是语法糖,异步本质还是回调函数
async/await 是消灭异步的终极武器JS 还是单线程,还是得有异步,还是得基于 event loopasync/await 只是语法糖,只是语法层面的同步写法
await 后面的内容,都可以看作是 callback 里的内容,即异步
for...of 的应用场景
for...in forEach for是常规的同步遍历for...of 常用于异步的遍历
微任务和宏任务
微任务:Promise async/awaitspan style=\"font-size: inherit;\
宏任务和微任务的区别
微任务执行时机比宏任务要早微任务:DOM 渲染前触发,如 Promise宏任务:DOM 渲染后触发,如 setTimeout
微任务:ES6 语法规定的宏任务:浏览器规定的
event loop 和 DOM 渲染的关系
JS 是单线程的,JS 执行和 DOM 渲染公用一个线程JS 执行的时候,得留一些时机供 DOM 渲染
每次 Call Stack 清空(即每次轮询结束),即同步任务执行完都是 DOM 重新渲染的机会,DOM 结构如有改变则重新渲染然后再去触发下一次 event loop
JS 异步进阶面试题
描述 event loop(事件循环/事件轮询)的机制,可画图
什么是宏任务和微任务,两者有什么区别?
Promise 有哪三种状态?有何变化?
场景题-Promise then 和 catch 的连接
第一题:1 3第二题:1 2 3第三题:1 2
场景题 - async/await 语法
第一题a: Promise.resolve(100)b: 100
第二题starta 100b 200Promise.reject() 会触发后续 catch,而 await 相当于 Promise 的 then因此 c await 那里报错,后续不再执行这里需要用 try...catch
场景题 - Promise 和 setTimeout 的顺序
100 400 300 200
场景题- 外加 async/awit 的顺序问题
sctipt startasync1 startasync2promise1script endasync1 endpromise2setTimeout
重点:微任务、宏任务执行的时机await 后面的代码都作为回调——微任务初始化 Promise 时, 传入的函数会立刻被执行
JS-Web-API
DOM
JS 基础知识,规定语法(ECMA 262 标准)JS Web API 网页操作的 API(W3C 标准)
DOM 的本质
树(DOM 树),DOM 的本质是 HTML 语言在浏览器中解析出来的树形结构
DOM 节点操作
获取 DOM 节点
getElementByIdgetElementsByTagNamegetElementsByClassNamequerySelectorAll
property 和 attribute
property 修改 JS 变量的属性,不会体现到标签结构中attribute 修改标签的属性,会改变标签结构两者都可能引起 DOM 重新渲染,尽量用 property
DOM 结构操作
添加节点:createElement插入节点:appendChild移动节点:对现有节点执行 appendChild,会移动节点删除节点:removeChild获取父元素:parentNode获取子元素:childNodes(过滤 nodeType 为1的子元素)
如何优化 DOM 操作的性能
DOM 操作非常“昂贵”,避免频繁的 DOM 操作:对 DOM 查询做缓存将频繁操作改为一次性操作(createDocumentFragment)
DOM 相关面试题
DOM 是那种数据结构
DOM 操作的常用 API
attribute 和 property 的区别
一次性插入多个 DOM 节点,考虑性能
BOM
navigator 浏览器信息
navigator.userAgent 识别浏览器类型
screen 屏幕信息
screen.widthscreen.height
location url 信息
location.href:整个网址 location.protocol:使用的协议,比如 'https:'、‘http:’location.host:域名location.pathname:路径lccation.search:url 的 query 参数location.hash:url 的 hash 值,比如 '#list'
history 历史信息
history.back()history.forward()
BOM 相关面试题
如何识别浏览器类型
分析拆解 url 各个部分
Ajax
XMLHttpRequest
Ajax 的核心 API
GET
xhr.responseText 为 json 字符串JSON.parse(xhr.responseText) 转 json 字符串为对象
POST
xhr.send() 需要发送 json 字符串JSON.stringify(postData) 转 json 对象为字符串
状态码
xhr.readyState
0 -(未初始化)还没有调用 send 方法1 -(载入)已调用 send 方法,正在发送请求2 -(载入完成)send 方法执行完成,已接受到全部响应内容3 -(交互)正在解析响应内容4 -(完成)响应内容解析完成,可在客户端调用
xhr.status
HTTP 协议的状态码:2xx:请求成功,2003xx:重定向,浏览器直接跳转,301永久,302临时,304资源未改变(用浏览器缓存资源)4xx:客户端请求错误,404访问地址找不到,403无权限访问5xx:服务端错误
跨域
同源策略
Ajax 请求时,浏览器要求当前网页和 server 必须同源(安全)同源:协议、域名、端口三者必须一致
加载图片 css js 可无视同源策略:<img/> 用于统计打点,可使用第三方统计服务<link /> <script> 可使用 CDN,CDN 一般都是外域<script/> 可实现 JSONP
实现跨域的常见方式 - JSONP 和 CROS
JSONP
<script> 可以绕过跨域限制服务器可以任意动态拼接数据返回所以,<script> 就可以获得跨域的数据,只要服务端愿意返回
jQuery 实现 jsonp
CROS - 服务器端 设置 http header
实际项目中 ajax 的常用工具
jQuery
fetch
新的 API,但要考虑兼容性
需要注意的问题:fetch 返回的 Promise 不会被标记为 reject,即使 HTTP 响应的状态码为400或500;仅当网络故障或请求被阻止时,才会标记为 reject。fetch 不会从服务端发送或接受任何 cookies,除非设置 credentials
axios
对 XMLHttpRequest 进行封装;支持 Promise
Ajax 相关面试题
手写一个简易的 Ajax
存储
cookie
本身用于浏览器和 server 通讯被“借用”到本地存储通过 document.cookie = '...' 来修改
cookie 的计算方式:同 key 覆盖,不同 key 追加
cookie 的缺点:存储太小,最大 4KB;http 请求时需要发送到服务端,增加请求数据量;只能用 document.cookie = '...' 来修改,过于简陋。
localStorage 和 sessionStorage
HTML5 专门为存储而设计,最大存 5MAPI 简单易用:setItem getItem不会随着 http 请求被发送出去
localStorage 数据会永久存储,除非代码或手动删除sessionStorage 数据只存在于当前会话,浏览器关闭则清空一般用 localStorage 更多
cookie localStorage sessionStorage 的区别
容量API 易用性是否跟随 http 请求发送出去
存储相关面试题
描述 cookie localStorage sessionStorage 的区别
JS-Web-API-事件
事件绑定
event.preventDefault 阻止默认行为(如:a链接跳转)event.target 获取触发的元素
事件冒泡
内部 DOM 的事件被触发,会导致外部的 DOM 元素绑定的事件也被触发
event.stopProgagation() 阻止冒泡
事件代理
基于于事件冒泡,将子元素触发的事件交给父元素的事件处理函数处理。
代码简洁减少浏览器内存占用不要滥用,用于瀑布流
事件相关面试题
编写一个通用的事件监听函数
描述事件冒泡的流程
基于 DOM 树形结构,事件会顺着触发元素往上冒泡
无限下拉的图片列表,如何监听每个图片的点击
事件代理用 e.target 获取触发元素用 matches 判断是否是触发元素
真题模拟
var 和 let const 的区别
var 是 ES5 语法,let const 是 ES6 语法;var 有变量提升var let 是变量,可修改;const 是常量,不可修改let const 有块级作用域,var 没有
var 有变量提升
typeof 返回哪些类型
值类型:undefined string number boolean symbol引用类型:object(typeof null === 'object') function
列举强制类型转换和隐式类型转换
强制:parseInt、parseFloat、toString 等隐式:if、逻辑运算、==、+拼接字符串
手写深度比较,模拟 lodash isEqual
关键点:递归
值类型,直接 === 比较=== 返回 true,返回true分别取 keys 比较个数,不相等返回 false,否则继续以 obj1 为基准,递归,递归到 false,返回 false,否则继续递归结束,返回 true
split() 和 join() 的区别
split()是将字符串以某个标识来分割为数组join()是将数组以某个标识来拼接为字符串
数组的 pop push unshift shift 分别做什么
pop() 删除数组的最后一个元素,并返回该元素的值;改变原数组
shift() 从数组中删除第一个元素,并返回该元素的值;改变原数组
push() 将一个或多个元素添加到数组的末尾,并返回该数组的新长度;改变原数组
unshift() 将一个或多个元素添加到数组的开头,并返回该数组的新长度;改变原数组
数组的 API 有哪些是纯函数
纯函数:变量都只在函数作用域内获取,作为函数的参数传入不会产生副作用,不会改变被传入的数据或者其他数据(全局变量)相同的输入保证相同的输出
concat() 用于合并两个或多个数组,返回新的数组;不改变原数组
map() 创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值;不改变原数组
slice() 返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end);不改变原数组
数组 slice 和 splice 的区别
slice 切片,纯函数
splice 剪接,非纯函数splice() 通过删除或替换现有元素或者原地添加新的元素来修改数组,返回修改后的该数组;改变原数组
拆解,发现问题在于参数 index
ajax 请求 get 和 post 的区别
get 一般用于查询,post 一般用于提交操作;get 参数拼接在 url 上,post 参数放在请求体内(数据体积可能更大)安全性:post 易于防止 CSRF
函数 call 和 apply 的区别
call 的参数拆分开传入,apply 的参数作为数组传入
事件代理(委托)是什么
在 body 上定义一个事件,然后去监听事件冒泡
闭包是什么?有什么特性?有什么负面影响?
应用场景:函数作为参数传入;函数作为返回值返回
自由变量的查找在函数定义的地方(非执行的地方)
影响:变量会常驻内存,得不到释放;闭包不要乱用
闭包有可能造成内存泄漏,但不一定:内存泄漏是变量在内存中应该被释放,但没有被释放;闭包是无法判断未来是否可用,而无法释放
如何阻止事件冒泡和默认行为?
event.stopPropagation()
event.preventDefault()
查找、添加、删除、移动 DOM 节点的方法
查找节点:getElementById,getElementsByTagName,getElementsByClassName,querySelector,querySelectorAll添加节点:createElement插入节点:appendChild移动节点:对现有节点执行 appendChild,会移动节点删除节点:removeChild获取父元素:parentNode获取子元素:childNodes(过滤 nodeType 为1的子元素)
如何减少 DOM 操作?
DOM 操作非常耗性能
缓存 DOM 查询结果多次 DOM 操作合并到一次插入
解释 jsonp 的原理,为何它不是真正的 ajax?
ajax 是通过 XMLHttpRequest 实现的jsonp 是通过 script 标签实现的
浏览器的同源策略和跨域
哪些 html 标签能绕过跨域?
img script
jsonp 的原理
jsonp 跨域需要后端支持,允许跨域
document load 和 ready 的区别
load - 页面的全部资源都加载完才会执行,包括图片、视频等ready - DOM 渲染完即可执行,此时图片、视频可能还没有加载完
让 JS 执行得更快,一般在 DOMContentLoaded 中执行
== 和 === 的区别
== 会尝试类型转换=== 严格相等只有一个场景用 ==:判断是 null 或 undefined 时
函数声明和函数表达式的区别
函数声明 function fn() {...}函数表达式 const fn = function () {...}函数声明会在代码执行前预加载,而函数表达式不会
new Object 和 Object.create() 的区别
{} 等同于 new Object(),原型 Object.prototypeObject.create(null) 没有原型Object.create({...}) 可指定原型
Object.create() 是创建一个空对象,把空对象的原型指向传入的对象
关于 this 的场景题
1 undefined
this 取值,在函数执行时确定
作用域和自由变量场景题
3 个 4
100 10 10
看一段代码:函数未执行,先跳过不看,执行时再看
常见的正则表达式
字符串,字母开头,后面字母数字下划线,长度6-30
正则表达式的规则
普通字符
[a-z] 匹配所有小写字母
[A-Z] 匹配所有大写字母
[\\s\\S] 匹配所有
\\w 匹配字母、数字、下划线;等价于 [A-Za-z0-9_]
\\d 匹配所有数字
非打印字符
\\s 匹配任何空白字符,包括空格、制表符、换页符等等
\\S 匹配任何非空白字符
\ 匹配一个换行符
\ 匹配一个回车符
\\t 匹配一个制表符
特殊字符
$ 匹配输入字符串的结尾位置
() 标记一个子表达式的开始和结束位置
* 匹配前面的子表达式零次或多次
+ 匹配前面的子表达式一次或多次
^ 匹配输入字符串的开始位置
限定字符
{n} \tn 是一个非负整数,匹配确定的 n 次
手写常见正则表达式
手写字符串 trim 方法,保证浏览器兼容性
如何获取多个数字中的最大值
arguments 类数组Array.prototype.slice.call(arguments) 将其变为数组
Math.min 取最小值
如何用 JS 实现继承
class 继承prototype 继承
如何捕获 JS 程序中的异常
什么是 JSON?
JSON 是一种数据格式,本质是一段字符串JSON 格和 JS 对象结构一致,对 JS 语言更友好window.JSON 是一个全局对象 JSON.stringify JSON.parse
key 字符串都需要用双引号
获取当前 url 的参数
传统方式
RegExp i 不区分大小写
URLSearchParams
注意浏览器兼容性
将 url 参数解析为 JS 对象
手写数组 flatern,考虑多层级
数组拍平
数组去重
传统方式,遍历数组,挨个比较去重
性能相对较差
使用 Set
Set 无序,不可重复,但兼容性较差
Object.assign 不是深拷贝
介绍一下 RAF(requestAnimationRequest)
JS 执行动画,要想动画流畅,更新频率要60帧/s,即 16.67ms 更新一次视图setTimeout 要收到控制频率,而 RAF 浏览器自动控制后台标签或隐藏 iframe 中,RAF 会暂停,而 setTimeout 依然执行
前端性能如何优化,一般从哪几个方面考虑?
原则:多使用内存、缓存,减少计算,减少网络请求
方向:页面加载,页面渲染,页面操作流畅度
0 条评论
回复 删除
下一页