判断 JS 类型的方式
1. typeof
可以判断出'string','number','boolean','undefined','symbol'
但判断 typeof(null) 时值为'object'; 判断数组和对象时值均为'object'
2. instanceof
原理是 构造函数的 prototype 属性是否出现在对象的原型链中的任何位置
- function A() {
- }
- let a = new A();
- a instanceof A //true, 因为 Object.getPrototypeOf(a) === A.prototype;
- 3. Object.prototype.toString.call()
常用于判断浏览器内置对象, 对于所有基本的数据类型都能进行判断, 即使是 null 和 undefined
4. Array.isArray()
用于判断是否为数组
浅拷贝和深拷贝
浅拷贝
- Object.assign()
- Array.prototype.slice()
扩展运算符 ...
深拷贝
JSON.parse(JSON.stringify())
递归函数
- function cloneObject (obj) {
- var newObj = {} // 如果不是引用类型, 直接返回
- if (typeof (obj) !== 'object') {
- return obj
- }
- // 如果是引用类型, 遍历属性
- else{
- for (var attr in obj) {
- // 如果某个属性还是引用类型, 递归调用
- newObj[attr] = cloneObject(obj[attr])
- }
- }
- return newObj
- }
如何实现一个深拷贝 https://juejin.im/post/5c45112e6fb9a04a027aa8fe
详细解析赋值, 浅拷贝和深拷贝的区别 https://juejin.im/post/5c20509bf265da611b585bec
数组去重的方法
1.ES6 的 Set
- let arr = [1,1,2,3,4,5,5,6]
- let arr2 = [...new Set(arr)]
- 2.reduce()
- let arr = [1,1,2,3,4,5,5,6]
- let arr2 = arr.reduce(function(ar,cur) {
- if(!ar.includes(cur)) {
- ar.push(cur)
- }
- return ar
- },[])
- 3.filter()
- // 这种方法会有一个问题:[1,'1']会被当做相同元素, 最终输入[1]
- let arr = [1,1,2,3,4,5,5,6]
- let arr2 = arr.filter(function(item,index) {
- // indexOf() 方法可返回某个指定的 字符串值 在字符串中首次出现的位置
- return arr.indexOf(item) === index
- })
DOM 事件有哪些阶段? 谈谈对事件代理的理解
分为三大阶段: 捕获阶段 -- 目标阶段 -- 冒泡阶段
事件代理简单说就是: 事件不直接绑定到某元素上, 而是绑定到该元素的父元素上, 进行触发事件操作时(例如'click'), 再通过条件判断, 执行事件触发后的语句(例如'alert(e.target.innerhtml)')
好处:(1)使代码更简洁;(2)节省内存开销
介绍下 promise.all
Promise.all()方法将多个 Promise 实例包装成一个 Promise 对象 (p), 接受一个数组(p1,p2,p3) 作为参数, 数组中不一定需要都是 Promise 对象, 但是一定具有 Iterator 接口, 如果不是的话, 就会调用 Promise.resolve 将其转化为 Promise 对象之后再进行处理.
使用 Promise.all()生成的 Promise 对象 (p) 的状态是由数组中的 Promise 对象 (p1,p2,p3) 决定的.
如果所有的 Promise 对象 (p1,p2,p3) 都变成 fullfilled 状态的话, 生成的 Promise 对象 (p) 也会变成 fullfilled 状态,
p1,p2,p3 三个 Promise 对象产生的结果会组成一个数组返回给传递给 p 的回调函数.
如果 p1,p2,p3 中有一个 Promise 对象变为 rejected 状态的话, p 也会变成 rejected 状态, 第一个被 rejected 的对象的返回值会传递给 p 的回调函数.
Promise.all()方法生成的 Promise 对象也会有一个 catch 方法来捕获错误处理, 但是如果数组中的 Promise 对象变成 rejected 状态时,
并且这个对象还定义了 catch 的方法, 那么 rejected 的对象会执行自己的 catch 方法.
并且返回一个状态为 fullfilled 的 Promise 对象, Promise.all()生成的对象会接受这个 Promise 对象, 不会返回 rejected 状态.
async 和 await
主要考察宏任务和微任务, 搭配 promise, 询问一些输出的顺序
原理: async 和 await 用了同步的方式去做异步, async 定义的函数的返回值都是 promise,await 后面的函数会先执行一遍, 然后就会跳出整个 async 函数来执行后面 JS 栈的代码
ES6 的 class 和构造函数的区别
class 的写法只是语法糖, 和之前 prototype 差不多, 但还是有细微差别的, 下面看看:
严格模式
类和模块的内部, 默认就是严格模式, 所以不需要使用 use strict 指定运行模式. 只要你的代码写在类或模块之中, 就只有严格模式可用. 考虑到未来所有的代码, 其实都是运行在模块之中, 所以 ES6 实际上把整个语言升级到了严格模式.
不存在提升
类不存在变量提升(hoist), 这一点与 ES5 完全不同.
- new Foo(); // ReferenceError
- class Foo {
- }
方法默认是不可枚举的
ES6 中的 class, 它的方法 (包括静态方法和实例方法) 默认是不可枚举的, 而构造函数默认是可枚举的. 细想一下, 这其实是个优化, 让你在遍历时候, 不需要再判断 hasOwnProperty 了
class 的所有方法 (包括静态方法和实例方法) 都没有原型对象 prototype, 所以也没有[[construct]], 不能使用 new 来调用.
class 必须使用 new 调用, 否则会报错. 这是它跟普通构造函数的一个主要区别, 后者不用 new 也可以执行.
ES5 和 ES6 子类 this 生成顺序不同
ES5 的继承先 生成了子类实例, 再 调用父类的构造函数修饰子类实例. ES6 的继承先 生成父类实例, 再 调用子类的构造函数修饰父类实例. 这个差别使得 ES6 可以继承内置对象.
ES6 可以继承静态方法, 而构造函数不能
transform,translate,transition 分别是什么属性? CSS 中常用的实现动画方式
三者属性说明
transform 是指变换, 变形, 是 css3 的一个属性, 和 width,height 属性一样;
translate 是 transform 的属性值, 是指元素进行 2D(3D)维度上位移或范围变换;
transition 是指过渡效果, 往往理解成简单的动画, 需要有触发条件.
这里可以补充下 transition 和 animation 的比较, 前者一般定义开始结束两个状态, 需要有触发条件; 而后者引入了关键帧, 速度曲线, 播放次数等概念, 更符合动画的定义, 且无需触发条件
介绍一下 rAF(requestAnimationFrame)
对 rAF 的阐述 MDN 资料
定时器一直是 JS 动画的核心技术, 但它们不够精准, 因为定时器时间参数是指将执行代码放入 UI 线程队列中等待的时间, 如果前面有其他任务队列执行时间过长, 则会导致动画延迟, 效果不精确等问题.
所以处理动画循环的关键是知道延迟多长时间合适: 时间要足够短, 才能让动画看起来比较柔滑平顺, 避免多余性能损耗; 时间要足够长, 才能让浏览器准备好变化渲染.
这个时候 rAF 就出现了, 采用系统时间间隔(大多浏览器刷新频率是 60Hz, 相当于 1000ms/60≈16.6ms), 保持最佳绘制效率, 不会因为间隔时间过短, 造成过度绘制, 增加开销; 也不会因为间隔时间太长, 使用动画卡顿不流畅, 让各种网页动画效果能够有一个统一的刷新机制. 并且 rAF 会把每一帧中的所有 DOM 操作集中起来, 在一次重绘或回流中就完成.
JavaScript 的垃圾回收机制讲一下
定义: 指一块被分配的内存既不能使用, 又不能回收, 直到浏览器进程结束.
像 C 这样的编程语言, 具有低级内存管理原语, 如 malloc()和 free(). 开发人员使用这些原语显式地对操作系统的内存进行分配和释放.
而 JavaScript 在创建对象 (对象, 字符串等) 时会为它们分配内存, 不再使用对时会 "自动" 释放内存, 这个过程称为垃圾收集.
内存生命周期中的每一个阶段:
分配内存 - 内存是由操作系统分配的, 它允许您的程序使用它. 在低级语言 (例如 C 语言) 中, 这是一个开发人员需要自己处理的显式执行的操作. 然而, 在高级语言中, 系统会自动为你分配内在.
使用内存 - 这是程序实际使用之前分配的内存, 在代码中使用分配的变量时, 就会发生读和写操作.
释放内存 - 释放所有不再使用的内存, 使之成为自由内存, 并可以被重利用. 与分配内存操作一样, 这一操作在低级语言中也是需要显式地执行.
四种常见的内存泄漏: 全局变量, 未清除的定时器, 闭包, 以及 dom 的引用
全局变量 不用 var 声明的变量, 相当于挂载到 Windows 对象上. 如: b=1; 解决: 使用严格模式
被遗忘的定时器和回调函数
闭包
没有清理的 DOM 元素引用
对前端性能优化有什么了解? 一般都通过那几个方面去优化的?
前端性能优化的七大手段
减少请求数量
减小资源大小
优化网络连接
优化资源加载
减少重绘回流
性能更好的 API
webpack 优化
前端安全也经常被问到的, 常见的有两种 --XSS,CSRF, 详见前端安全
找到工作前还会不定期补充, 未完待续...
来源: https://www.cnblogs.com/chenwenhao/p/11253403.html