CSS部分
- flex:1全称表示什么
- animation动画(keyFrame动画)
- 瀑布流的布局
- 抽屉布局
- 圣杯布局和双飞翼布局
js部分
- 手写typeof
function getType (temp) {
let str = temp.constructor.toString()
return str.slice(9, str.indexOf('(')).toLowerCase()
}
- this指针
- 原型链
- 让 a == 1 && a == 2 && a ==3 为true
// 方法一:
let val = 1
Object.defineProperty(window, 'a', { configurable: true, get: function () {
return val++
} })
if (a == 1 && a == 2 && a == 3) {
console.log('可以')
} else {
console.log('不可以')
}
// 方法二:
const a = {
i: 1,
toString: function () {
return this.i++
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('可以')
} else {
console.log('不可以')
}
- 异步函数Promise
- 手写Promise.race
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject)
}
})
}
- 闭包(防抖和节流)
- es5和es6中继承
- 深拷贝和浅拷贝
- import和require的区别
- forEach和map的区别
- 实现一个bind函数 最简单的写法
bind() {
let that = this;
return function () {
that.apply(arguments)
}
}
重写函数原型上的bind函数
if (!Function.prototype.bind){
Function.prototype.bind = function () {
let that = this
let context = [].shift.call(arguments)
let args = [].slice.call(arguments)
return function () {
that.apply(context,args.concat([].slice.apply(arguments)))
}
}
- 宏任务、微任务
console.log('start: 开始执行')
async function async1() {
console.log(1)
await async2()
console.log(2)
}
async function async2() {
console.log(3)
async function async3() {
console.log(4)
await setTimeout(function () {
console.log(5)
}, 0)
}
async3()
}
console.log(6)
async1()
setTimeout(function () {
console.log('end: 结束所有任务')
}, 0)
new Promise(function (resolve, reject) {
console.log(8)
resolve()
}).then(function () {
console.log(9)
}).finally(function () {
console.log('微任务执行完毕')
})
console.log('同步任务执行结束')
结果:
start: 开始执行
6
1
3
4
8
同步任务执行结束
2
9
微任务执行完毕
5
end: 结束所有任务
- flat的作用
Array.prototype.myFlat = function (d = 1) {
let arr = [...this]
return d > 0 ? arr.reduce((acc, val) => {
return acc.concat(Array.isArray(val) ? val.myFlat(d - 1) : val)
}, []) : arr.slice()
}
- Promise.all原理
Promise.myAll = function (arr) {
let arrResult = []
let count = 0
let len = arr.length
return new Promise(function (resolve, reject) {
for (let i = 0; i < arr.length; i++) {
Promise.resolve(arr[i]).then(function (res) {
arrResult[i] = res
count++
if (count === len) {
return resolve(arrResult)
}
}, function (err) {
return reject(err)
})
}
})
}
let p1 = Promise.resolve(3);
let p2 = 1337;
let p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.myAll([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
- promise.all限制请求个数
Promise.myAll = function (arr, limit) {
let arrResult = []
let count = 0
let len = arr.length
return new Promise(function (resolve, reject) {
for (let i = 0; i < limit; i++) {
Promise.resolve(arr[i]).then(function (res) {
arrResult[i] = res
count++
if (count === len) {
return resolve(arrResult)
} else {
if (count < len) {
return continueStart(arr, count, resolve, reject, arrResult, len)
}
}
}, function (err) {
return reject(err)
})
}
})
}
function continueStart(arr, i, resolve, reject, arrResult, len) {
return Promise.resolve(arr[i]).then(function (res) {
arrResult[i] = res
if (arrResult.length === len) {
return resolve(arrResult)
} else {
let count = arrResult.length
if (count < len) {
return continueStart(arr, count, resolve, reject, arrResult, len)
}
}
}, function (err) {
return reject(err)
})
}
- 深copy
function deepClone(obj) {
let arr = Array.isArray(obj) ? [] : {}
if (obj && typeof obj === 'object') {
for (let item in obj) {
if (obj[item] && typeof obj[item] === 'object') {
arr[item] = deepClone(obj[item])
} else {
arr[item] = obj[item]
}
}
}
return arr
}
Vue部分
- 组件间传值的几种方式
1、props/$emit
2、$emit/$on
3、Vuex
4、$attrs/$listeners
5、provide/inject
6、$parrent/$children 、ref
- $emit作用和原理
$emit也是采用了发布订阅者设计模式。
Vue.prototype.$emit = function (event: string): Component {
const vm: Component = this
let cbs = vm._events[event]
if (cbs) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs
const args = toArray(arguments, 1)
for (let i = 0, l = cbs.length; i < l; i++) {
try {
cbs[i].apply(vm, args)
} catch (e) {
handleError(e, vm, `event handler for "${event}"`)
}
}
}
return vm
}
}
根据传入的事件名从当前实例的_events属性(即事件中心)中获取到该事件名所对应的回调函数cbs,然后再获取传入的附加参数args,由于cbs是一个数组,所以遍历该数组,拿到每一个回调函数,执行回调函数并将附加参数args传给该回调。
- watch、computed区别和原理
- router的原理
- 双向绑定的原理
- mixins的原理
- vue如何监听到数组和对象的变化
- template如何模板转化
- 虚拟Dom的实现原理
http部分
- DNS解析流程
- htts的工作流程
- 1、客户端发起HTTPS请求
- 2、服务端的配置
- 3、传送证书
- 4、客户端解析证书
- 5、传送加密信息
- 6、服务端解密信息
- 7、传输加密后的信息
- 8、客户端解密信息
Client发起一个HTTPS(https:/demo.linianhui.dev)的请求,根据RFC2818的规定,Client知道需要连接Server的443(默认)端口。 Server把事先配置好的公钥证书(public key certificate)返回给客户端。 Client验证公钥证书:比如是否在有效期内,证书的用途是不是匹配Client请求的站点,是不是在CRL吊销列表里面,它的上一级证书是否有效,这是一个递归的过程,直到验证到根证书(操作系统内置的Root证书或者Client内置的Root证书)。如果验证通过则继续,不通过则显示警告信息。 Client使用伪随机数生成器生成加密所使用的会话密钥,然后用证书的公钥加密这个会话密钥,发给Server。 Server使用自己的私钥(private key)解密这个消息,得到会话密钥。至此,Client和Server双方都持有了相同的会话密钥。 Server使用会话密钥加密“明文内容A”,发送给Client。 Client使用会话密钥解密响应的密文,得到“明文内容A”。 Client再次发起HTTPS的请求,使用会话密钥加密请求的“明文内容B”,然后Server使用会话密钥解密密文,得到“明文内容B”。
webpack
- webpack打包流程
- 常见的loader及其作用
- 打包优化
算法
- 斐波那契系数
- LRU缓存机制
function LinkNode(key, val) {
this.key = key
this.val = val
this.next = null
this.pre = null
}
function DoubleLinkList() {
this.size = 0
this.head = new LinkNode()
this.last = new LinkNode()
this.head.next = this.last
this.last.pre = this.head
}
DoubleLinkList.prototype.addNode = function (node) {
if (!(node instanceof LinkNode)) throw new Error('参数必须是LinkNode类型')
// 尾插入法
const preNode = this.last.pre
const nextNode = this.last.pre.next
node.pre = preNode
node.next = nextNode
preNode.next = node
nextNode.pre = node
this.size++
}
DoubleLinkList.prototype.deleteNode = function (node) {
if (!(node instanceof LinkNode)) throw new Error('参数必须是LinkNode类型')
const preNode = node.pre
const nextNode = node.next
preNode.next = nextNode
nextNode.pre = preNode
this.size--
}
DoubleLinkList.prototype.refreshList = function (node) {
this.deleteNode(node)
this.addNode(node)
}
function LRUCatch(limit) {
this.maxSize = limit
this.map = new Map()
this.doubleLinkList = new DoubleLinkList()
}
LRUCatch.prototype.get = function (key) {
if (this.map.get(key) === undefined) return -1
const curNode = this.map.get(key)
this.doubleLinkList.refreshList(curNode)
return curNode.val
}
LRUCatch.prototype.put = function (key, val) {
const newNode = new LinkNode(key, val)
// 如果存在,更新val
if (this.map.get(key)) {
this.doubleLinkList.refreshList(this.map.get(key))
return this.map.get(key).val = val
}
if (this.map.size < this.maxSize) { // 空间足够时
this.doubleLinkList.addNode(newNode)
} else {
// 清理链表中的头部节点
const firstNode = this.doubleLinkList.head.next
this.doubleLinkList.deleteNode(firstNode)
this.doubleLinkList.addNode(newNode)
// 删除哈希表中的key
this.map.delete(firstNode.key)
}
this.map.set(key, newNode)
}
其他
- vue-cli都做了什么
- shell指令 (自动化打包)
- npm源发布自己打包的工具
- 网页打包优化
- Vue优化
Object.freeze()可以使响应式数据变成普通数据