# 2020 / 3 / 8
内容出自掘友「WaterMan」 入口:https://juejin.im/post/5c19c1b6e51d451d1e06c163#heading-2
# 腾讯
# 1 / 知道什么是事件委托吗?
所谓事件委托,就是利用事件冒泡的原理,将自己所触发的事件,让父元素代替执行
即:不在触发事件的元素(直接Dom)上设置监听事件,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生在哪一个子元素上来做出不同的响应
为什么要使用事件委托?
- 提高性能
- 新增加的元素也能触发绑定在父元素上的监听事件
# 2 / 对Promise了解吗?(主观)
Promise是异步编程得一种常见方法,它是一个对象,通过它可以获取异步操作的结果,做出相应的回调
Promise对象具有以下特点:
- Promise的状态不受外界影响,Promise对象代表一个异步操作,具有三种状态:pending(等待态),fulfilled(完成态),rejected(失败态)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
- 一旦状态改变,就不会再次改变
- 任何时候都可以得到结果
Promise对象的状态改变,只有两种可能:
- pending → fufilled
- pending → rejected
只要这两种情况发生,状态就凝固了(不再发生变化),会一致保持这个结果,这时就称为resolved(已定型),如果改变已经发生,再对Promise对象添加相应回调(then()/catch()),也会立即得到这个结果
# 3 / 你之前遇到过跨域问题吗?是怎么解决的
解决跨域的方法:
- jsonp(仅能处理get)
- cors(服务端设置响应头 Access-Control-Allow-Origin)
- window.name(利用浏览器窗口内,载入所有的域名都共享一个window.name)
- document.domain / window.postMessage()
# 4 / 代码题
有一个类如下:
function Person(name){
this.name = name
}
let p = new Person('Tom')
2
3
4
p.proto 等于什么? 答:Person.prototype
Person.proto 等于什么? 答:Function.prototype
# 5 / typeof 和 instanceof 的区别
- typeof
- 能够正确判断简单数据类型(原始类型),除了null以外,因为 typeof null = 'object'
- 对于对象而已,typeof 不能正确判断对象类型,typeof仅可以区分开function,除此之外,结果均为 object
- instanceof
- 能够准确判断复杂数据类型,但是不能正确判断简单数据类型
- 原理:通过原型链判断
# 6 / new & instanceof的内部机制
- new
- 创建一个新对象(空对象)
- 对这个新对象进行原型链接
- 将this指向新创建的对象,并执行构造函数中的方法
- 如果函数没有返回其他对象,那么this指向这个新对象,否则this指向构造函数返回的对象
· 手写new
function myNew(){
const obj = function(){}
const Constructor = [].shift.call(arguments) // 删除第一个参数并获取这个参数
obj.__proto__ = Constructor.prototype
const returnObj = Constructor.apply(obj, arguments) // this指向这个新对象,并且执行构造函数
return typeof returnObj === 'object' ? returnObj : obj
}
2
3
4
5
6
7
8
9
10
- instanceof
- 通过原型链进行判断,例如 A instanceof B,在A的原型链中层层查找,查找是否有原型等于 B.prototype,如果一直找到A的原型链顶端(Object.prototype.proto),仍然找不到,那么返回 false,否则返回 true
· 手写 instanceof
function myInstanceof(left, right){
let rightPrototype = right.prototype
let leftPrototype = left.__proto__
while(true){
if(leftPrototype === null) return false
if(leftPrototype === rightPrototype) {
return true
}
leftPrototype = leftPrototype.__proto__
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 7 / 下面代码输出什么?
for(var i = 0; i < 10; i++){
setTimeout(() => {
console.log(i)
}, 0)
}
2
3
4
5
答:输出10个10
追问:如何输出0-9?
- 闭包
for(var i = 0; i < 10; i++){
(function(j){
setTimeout(() => {
console.log(j)
},0)
})(i)
}
2
3
4
5
6
7
- var 改为 let
for(let i = 0; i < 10; i++){
setTimeout(() => {
console.log(i)
}, 0)
}
2
3
4
5
# 8 / 说一下箭头函数This指向问题?
箭头函数没有自己的this,当我们使用箭头函数时,箭头函数会默认帮我们将绑定外层this的值,即箭头函数的this值与外层的this值一致
# 9 / for...in迭代和for...of有什么区别?
- for in
- 遍历对象及其原型链上可枚举的属性
- 如果用于遍历数组,除了遍历其元素外,还会遍历数组对象自定义的可枚举属性及其原型链上的可枚举属性
- 遍历对象返回的属性名和遍历数组返回的索引都是字符串类型
- 某些情况,可能按随机顺序遍历数组元素
- for of
- 支持遍历数组,类数组对象,字符串,Map对象,Set对象
- 不支持遍历普通对象
- 遍历后输出的结果是索引值(for in是索引)
# 10 / 使用过flex布局吗?flex-grow和flex-shrink属性有什么用?
- flex-grow:用于项目的放大比例,默认为0,即存在剩余空间,也不放大
- flex-shrink:用于项目的缩小比例,默认为1,即空间不足时,该项目将缩小
# 11 / Http请求中的keep-alive有了解吗?
传统的Http都是一次Tcp连接一次request,这种情况效率较低,而在http1.1协议中添加了keep-alive的支持,并默认开启
客户端和服务器在建立连接并完成request后并不会立即断开Tcp连接,而是在下次request时复用这次Tcp连接,但这里也必须要有Tcp连接的timeout时间限制,不然会造成服务器端口被长期占用。
使用keep-alive可以在一次Tcp连接中持续发送多份数据,通过keep-alive减少Tcp连接次数,以此提高性能和提高http服务器的吞吐量。
长时间的Tcp连接容易导致系统资源无效占用,配置不当的keep-alive,有时损失更大,所以正确配置keep-alive的timeout时间非常重要
# 12 / 数组扁平化处理:实现一个flatten方法,使得输入一个数组,该数组里面的元素也可以是数组,该方法会输出一个扁平化的数组
function flatten(arr){
return arr.reduce(function(prev, item){
return prev.concat(Array.isArray(item) ? flatten(item) : item)
},[])
}
2
3
4
5
一行代码解决:
Array.from(new Set(arr.flat(infinity))).sort((a, b) => { return a - b})