JavaScript
2021-03-24 15:02:30 0 举报
AI智能生成
前端面试_JavaScript
作者其他创作
大纲/内容
JS 基础
变量类型和计算
JS 值类型和引用类型的区别
值类型
深入分析
引用类型
深入分析
浅拷贝:复制的时候只拷贝内存地址
栈从上往下排列,堆从下往上排列
考虑性能和存储
常见值类型
常见引用类型
手写 JS 深拷贝
typeof 运算符
判断所有值类型
判断函数,能识别引用类型(不能再继续识别)
深拷贝
浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址;
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存。
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存。
变量计算 - 类型转换
字符串拼接
== 运算符
只有一个地方用 == :判断是 null 或 undefined 时,其他一律用 ===
if 语句和逻辑运算
- truly 变量:!!a === true 的变量
- falsely 变量:!!a === false 的变量
if 语句,就是判断 truly 变量 和 falsely 变量
逻辑判断
变量类型相关面试题
typeof 能判断哪些类型?
何时使用 ===,何时使用 ==?
值类型和引用类型的区别
手写深拷贝
原型和原型链
如何用 class 实现继承
class
- constructor
- 属性
- 方法
继承
- extends
- super
- 扩展或重写方法
示例
如何理解 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
向上级作用域,一层一层依次寻找,直到找到为止;如果到全局作用域都没找到,则报错:xxx is not defined
闭包
作用域应用的特殊情况,有两种表现:
- 函数作为参数被传递
- 函数作为返回值被返回
函数作为参数
函数作为返回值
闭包就是能够读取其他函数内部变量的函数
所有的自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方!!!
this
this 应用场景
- 作为普通函数被调用
- 使用 call apply bind 调用
- 作为对象方法被调用
- 在 class 方法中 调用
- 箭头函数
普通函数,call,bind
call,apply,bind 都可以改变 this,不同的是:
- call 的参数是直接放进去的,参数全都用逗号分隔;
- apply 的所有参数都必须放在一个数组里面传进去;
- bind 要返回一个新的函数去执行,call apply 调用则执行。
对象方法
是 setTimeout 触发的执行(window.setTimeout),而不是 zhangsan 这个对象触发的执行,因此 this 指向 window
箭头函数
箭头函数里的 this 永远取它上级作用域的 this
class
this 取什么样的值,是在函数执行的时候确定的,不是在函数定义的时候确定的!!!
作用域相关面试题
this 的不同应用场景,如何取值?
手写 bind 函数
Array.prototype.slice.call(arguments) 能将具有 length 属性的对象转成数组
- argument 为类数组
- slice 从已有的数组中返回选定的元素
- slice 方法可以用来将一个类数组对象/集合转换成一个新数组,只需将该方法绑定到这个对象上。
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值;
pop() 方法用于把数组的最后一个元素从其中删,并返回最后一个元素的值。
pop() 方法用于把数组的最后一个元素从其中删,并返回最后一个元素的值。
实际开发中闭包的应用场景,举例说明
闭包隐藏数据,只提供 API
创建 10 个 a 标签,点击的时候弹出对应的序号
注意 let i 写在 for 里,for 里的块级作用域;
若写在 for 外面,是全局作用域,for 一次性执行完,点击时 i 均为10
若写在 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 解决 callback hell 的问题, 依然是 callback 回调,但不再是多层嵌套,而是链式调用
异步相关面试题
同步和异步的区别是什么?
手写 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:调用栈
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 或 catch
- resolved:会触发后续的 then 回调函数
- rejected:会触发后续的 catch 回调函数
Promise 的 then 和 catch 如何影响状态的变化
then/catch
- 正常返回 resolved 状态的 Promise(会触发后续的 then 回调函数)
- 里面有报错则返回 rejected 状态的 Promise(会触发后续的 catch 回调函数)
async/await
背景
- 异步回调 callback hell
- Promise then catch 链式调用,但还是基于回调函数
- async/await 是同步语法,彻底消灭回调函数
基本使用
await 必须放在 async 函数中,否则会报错
async/await 和 Promise 的关系
async/await 消灭异步回调,但和 Promise 并不互斥,相辅相成
- 执行 async 函数,返回的是一个 Promise 对象
- await 相当于 Promise 的 then
- try...catch 可捕获异常,相当于 Promise 的 catch
async/await 是语法糖,异步本质还是回调函数
- async/await 是消灭异步的终极武器
- JS 还是单线程,还是得有异步,还是得基于 event loop
- async/await 只是语法糖,只是语法层面的同步写法
await 后面的内容,都可以看作是 callback 里的内容,即异步
for...of 的应用场景
- for...in forEach for是常规的同步遍历
- for...of 常用于异步的遍历
微任务和宏任务
- 微任务:Promise async/await
- 宏任务:setTimeout,setInterval, Ajax, DOM事件
宏任务和微任务的区别
微任务执行时机比宏任务要早
- 微任务: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
a: Promise.resolve(100)
b: 100
第二题
start
a 100
b 200
Promise.reject() 会触发后续 catch,而 await 相当于 Promise 的 then
因此 c await 那里报错,后续不再执行
这里需要用 try...catch
start
a 100
b 200
Promise.reject() 会触发后续 catch,而 await 相当于 Promise 的 then
因此 c await 那里报错,后续不再执行
这里需要用 try...catch
场景题 - Promise 和 setTimeout 的顺序
100 400 300 200
场景题- 外加 async/awit 的顺序问题
sctipt start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
重点:
- 微任务、宏任务执行的时机
- await 后面的代码都作为回调——微任务
- 初始化 Promise 时, 传入的函数会立刻被执行
JS-Web-API
DOM
- JS 基础知识,规定语法(ECMA 262 标准)
- JS Web API 网页操作的 API(W3C 标准)
DOM 的本质
树(DOM 树),DOM 的本质是 HTML 语言在浏览器中解析出来的树形结构
DOM 节点操作
获取 DOM 节点
- getElementById
- getElementsByTagName
- getElementsByClassName
- querySelectorAll
property 和 attribute
- property 修改 JS 变量的属性,不会体现到标签结构中
- attribute 修改标签的属性,会改变标签结构
DOM 结构操作
添加节点:createElement
插入节点:appendChild
移动节点:对现有节点执行 appendChild,会移动节点
删除节点:removeChild
获取父元素:parentNode
获取子元素:childNodes(过滤 nodeType 为1的子元素)
插入节点: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.width
screen.height
screen.height
location url 信息
location.href:整个网址
location.protocol:使用的协议,比如 'https:'、‘http:’
location.host:域名
location.pathname:路径
lccation.search:url 的 query 参数
location.hash:url 的 hash 值,比如 '#list'
location.protocol:使用的协议,比如 'https:'、‘http:’
location.host:域名
location.pathname:路径
lccation.search:url 的 query 参数
location.hash:url 的 hash 值,比如 '#list'
history 历史信息
history.back()
history.forward()
history.forward()
BOM 相关面试题
如何识别浏览器类型
分析拆解 url 各个部分
Ajax
XMLHttpRequest
Ajax 的核心 API
GET
xhr.responseText 为 json 字符串
JSON.parse(xhr.responseText) 转 json 字符串为对象
JSON.parse(xhr.responseText) 转 json 字符串为对象
POST
xhr.send() 需要发送 json 字符串
JSON.stringify(postData) 转 json 对象为字符串
JSON.stringify(postData) 转 json 对象为字符串
状态码
xhr.readyState
- 0 -(未初始化)还没有调用 send 方法
- 1 -(载入)已调用 send 方法,正在发送请求
- 2 -(载入完成)send 方法执行完成,已接受到全部响应内容
- 3 -(交互)正在解析响应内容
- 4 -(完成)响应内容解析完成,可在客户端调用
xhr.status
HTTP 协议的状态码:
- 2xx:请求成功,200
- 3xx:重定向,浏览器直接跳转,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 专门为存储而设计,最大存 5M
- API 简单易用:setItem getItem
- 不会随着 http 请求被发送出去
- localStorage 数据会永久存储,除非代码或手动删除
- sessionStorage 数据只存在于当前会话,浏览器关闭则清空
- 一般用 localStorage 更多
cookie localStorage sessionStorage 的区别
- 容量
- API 易用性
- 是否跟随 http 请求发送出去
存储相关面试题
描述 cookie localStorage sessionStorage 的区别
JS-Web-API-事件
事件绑定
target.addEventListener(type, listener, options);
event.preventDefault 阻止默认行为(如:a链接跳转)
event.target 获取触发的元素
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
引用类型:object(typeof null === 'object')
function
列举强制类型转换和隐式类型转换
强制:parseInt、parseFloat、toString 等
隐式:if、逻辑运算、==、+拼接字符串
隐式:if、逻辑运算、==、+拼接字符串
手写深度比较,模拟 lodash isEqual
关键点:递归
- 值类型,直接 === 比较
- === 返回 true,返回true
- 分别取 keys 比较个数,不相等返回 false,否则继续
- 以 obj1 为基准,递归,递归到 false,返回 false,否则继续
- 递归结束,返回 true
split() 和 join() 的区别
split()是将字符串以某个标识来分割为数组
join()是将数组以某个标识来拼接为字符串
join()是将数组以某个标识来拼接为字符串
数组的 pop push unshift shift 分别做什么
pop() 删除数组的最后一个元素,并返回该元素的值;改变原数组
shift() 从数组中删除第一个元素,并返回该元素的值;改变原数组
push() 将一个或多个元素添加到数组的末尾,并返回该数组的新长度;改变原数组
unshift() 将一个或多个元素添加到数组的开头,并返回该数组的新长度;改变原数组
数组的 API 有哪些是纯函数
纯函数:
- 变量都只在函数作用域内获取,作为函数的参数传入
- 不会产生副作用,不会改变被传入的数据或者其他数据(全局变量)
- 相同的输入保证相同的输出
concat() 用于合并两个或多个数组,返回新的数组;不改变原数组
var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
map() 创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值;不改变原数组
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
// Return element for new_array
}[, thisArg])
filter() 创建一个新数组, 其包含通过所提供函数实现的测试的所有元素;不改变原数组
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
slice() 返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end);不改变原数组
arr.slice([begin[, end]])
数组 slice 和 splice 的区别
slice 切片,纯函数
splice 剪接,非纯函数
- splice() 通过删除或替换现有元素或者原地添加新的元素来修改数组,返回修改后的该数组;改变原数组
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
[10, 20, 30].map(parseInt) 返回结果是什么
[10, NaN, NaN]
拆解,发现问题在于参数 index
parseInt(10, 0) // 10
parseInt(20, 1) // NaN
parseInt(30, 2) // NaN
parseInt(20, 1) // NaN
parseInt(30, 2) // NaN
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的子元素)
添加节点:createElement
插入节点:appendChild
移动节点:对现有节点执行 appendChild,会移动节点
删除节点:removeChild
获取父元素:parentNode
获取子元素:childNodes(过滤 nodeType 为1的子元素)
如何减少 DOM 操作?
DOM 操作非常耗性能
- 缓存 DOM 查询结果
- 多次 DOM 操作合并到一次插入
解释 jsonp 的原理,为何它不是真正的 ajax?
- ajax 是通过 XMLHttpRequest 实现的
- jsonp 是通过 script 标签实现的
浏览器的同源策略和跨域
Ajax 请求时,浏览器要求当前网页和 server 必须同源(安全)
同源:协议、域名、端口三者必须一致
同源:协议、域名、端口三者必须一致
哪些 html 标签能绕过跨域?
img script
jsonp 的原理
jsonp 跨域需要后端支持,允许跨域
document load 和 ready 的区别
load - 页面的全部资源都加载完才会执行,包括图片、视频等
ready - DOM 渲染完即可执行,此时图片、视频可能还没有加载完
ready - DOM 渲染完即可执行,此时图片、视频可能还没有加载完
让 JS 执行得更快,一般在 DOMContentLoaded 中执行
== 和 === 的区别
- == 会尝试类型转换
- === 严格相等
- 只有一个场景用 ==:判断是 null 或 undefined 时
函数声明和函数表达式的区别
- 函数声明 function fn() {...}
- 函数表达式 const fn = function () {...}
- 函数声明会在代码执行前预加载,而函数表达式不会
new Object 和 Object.create() 的区别
- {} 等同于 new Object(),原型 Object.prototype
- Object.create(null) 没有原型
- Object.create({...}) 可指定原型
Object.create() 是创建一个空对象,把空对象的原型指向传入的对象
关于 this 的场景题
1 undefined
this 取值,在函数执行时确定
作用域和自由变量场景题
3 个 4
100 10 10
看一段代码:函数未执行,先跳过不看,执行时再看
常见的正则表达式
字符串,字母开头,后面字母数字下划线,长度6-30
const reg = /^[a-zA-Z]\w{5,29}$/
正则表达式的规则
普通字符
[a-z] 匹配所有小写字母
[A-Z] 匹配所有大写字母
[\s\S] 匹配所有
\w 匹配字母、数字、下划线;等价于 [A-Za-z0-9_]
\d 匹配所有数字
非打印字符
\s 匹配任何空白字符,包括空格、制表符、换页符等等
\S 匹配任何非空白字符
\n 匹配一个换行符
\r 匹配一个回车符
\t 匹配一个制表符
特殊字符
$ 匹配输入字符串的结尾位置
() 标记一个子表达式的开始和结束位置
* 匹配前面的子表达式零次或多次
+ 匹配前面的子表达式一次或多次
^ 匹配输入字符串的开始位置
限定字符
{n} n 是一个非负整数,匹配确定的 n 次
{n,} n 是一个非负整数,至少匹配n 次
{n,m} m 和 n 均为非负整数,其中n <= m;最少匹配 n 次且最多匹配 m 次
手写常见正则表达式
手写字符串 trim 方法,保证浏览器兼容性
replace(/^\s+/, '') 命中开头的一个或多个空字符串,替换为''
replace(/\s+$/, '') 命中结尾的一个或多个空字符串,替换为''
如何获取多个数字中的最大值
arguments 类数组
Array.prototype.slice.call(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 对象
传统方式
URLSearchParams
手写数组 flatern,考虑多层级
数组拍平
数组去重
传统方式,遍历数组,挨个比较去重
性能相对较差
使用 Set
Set 无序,不可重复,但兼容性较差
手写深拷贝
Object.assign 不是深拷贝
介绍一下 RAF(requestAnimationRequest)
- JS 执行动画,要想动画流畅,更新频率要60帧/s,即 16.67ms 更新一次视图
- setTimeout 要收到控制频率,而 RAF 浏览器自动控制
- 后台标签或隐藏 iframe 中,RAF 会暂停,而 setTimeout 依然执行
前端性能如何优化,一般从哪几个方面考虑?
原则:多使用内存、缓存,减少计算,减少网络请求
方向:页面加载,页面渲染,页面操作流畅度
0 条评论
下一页