Open Linjiayu6 opened 4 years ago
实现caller
npm 版本规则
websocket polling
笔试 css九宫格 异步任务并发数限制
js array string api https://www.jianshu.com/p/5477e281c30e
1. 懒加载与动态 import 语法的坑
3. 说说怎么本地调试 npm 包,考察 npm link
6. Tree-shaking 原理
7. 微前端了解多少,如果让你做微前端的技术选型,你怎么考虑
8. 疯狂问项目,思考和看法
11. Node 框架用的什么, Koa 与 Express 相比有什么不同
12. Node 服务部署,运维 / node容灾处理 🔥 / node如何捕获异常 🔥
13. 懒加载怎么做 / 懒加载原理实现方法 🔥 🔥
15. Node 底层了解多少
17. 用户弱网环境问题排查与优化
19. SSO 鉴权流程
24. 如何自己实现一个组件按需加载
30. Node Stream 是干什么的
34. async 的异常捕获
42. 聊聊尾递归 / 尾递归函数优化 🔥
47. 扫码登录的实现逻辑
56. 算法,最大连续子序列(dp) 🔥
67. 将json字符串'{"a": 1, "b": "str", "c":[2, 3], "d":{"e": 4}}'
69. 给定一个数组,求该数组所有的自子数组
78. 买卖股票一次获得的最大利润(动态规划) 🔥
82. 对flutter的了解 🔥
1. 单链表的对折 🔥
2. 块级作用域 IIFE 🔥 🔥 🔥
3. 你项目怎么接入ci的,整个流水线是怎样【描述】
git提交 => lint执行 => 触发hook => 读取yml文件执行命令 => 部署 => 调用机器人接口发布企业微信群周知
4. web worker 🔥
https://leetcode-cn.com/problems/add-two-numbers/
面试可参考 Google面试 2020年前端面试复习必读精选文章
/**
* fn.apply(context, [xxx])
* fn.call(context, a, b, c, ...)
* fn.bind(context)(a, b, c)
*/
Function.prototype._call_ = function (context) {
var context = Object(context) || window // Object() 自动包装对象
// let args = [...arguments].slice(1);
const args = Array.prototype.slice.call(arguments, 1)
// 放在对象或window去执行, this是 调用该方法的函数 eg: A.call(xxx), this 是 A
context.fn = this
var result = context.fn(...args)
delete context.fn
return result
}
function fn (...args) { console.log(this.a, args) }
const obj = { a: 1, b: 2}
fn._call_(obj, '参数')
Function.prototype._apply_ = function (context) {
var context = context || window
const args = Array.prototype.slice.call(arguments, 1)
context.fn = this
context.fn(...args)
delete context.fn
}
fn._apply_(obj, [1, 2, 3])
Function.prototype._bind_ = function (context) {
context = context || window
let args = Array.prototype.slice.call(arguments, 1)
const fn = this
return function () {
const bindArgs = Array.prototype.slice.call(arguments, 0)
return fn.apply(context, args.concat(bindArgs))
// 或 fn.call(context, ...argList)
}
}
const obj = { name: 1 }
function executor (age, unv) {
console.log(this.name)
console.log(age)
console.log(unv)
}
executor._bind_(obj)(18, 'hkbu')
/**
* 【debounce 防抖】
* 场景: 输入框输入查询内容,接口请求,新内容都需要每次都重新请求接口
* 触发后, 如果有重复触发的, 都再次重新执行
* 【throttle 节流】
* 场景: 避免多次触发 例如已经提交过的, 在处理中的不允许再次提交
* eg: 往下拉刷新接口等,需要锁住 防止多次下拉刷新提交
* 正在执行的, 不允许触发执行
*/
const throttle = (fn, delay) => {
let flag = true
return (...args) => {
if (flag === false) return
flag = false
setTimeout(() => {
fn.call(this, ...args) // 这里容易错
flag = true
}, delay)
}
}
const debounce = (fn, delay) => {
let timer = null
return (...args) => {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
[对象key值遍历] Object.keys = for in + hasOwnProperty
[类型判断] Object.prototype.toString.call(value) [object Object] 类型判断
[队列从头pop] array.shift()
### 浅拷贝
```javascript
const shallowClone = target => {
// for in + hasOwnProperty 或 Object.keys()
const result = {}
for (let key in target) {
if (target.hasOwnProperty(key)) {
result[key] = target[key]
}
}
return result
}
const deepClone1 = target => {
const result = {}
Object.keys(target).forEach(key => {
const value = target[key]
// Object.prototype.toString.call(value) 类型判断
if (Object.prototype.toString.call(value) === '[object Object]') {
result[key] = deepClone1(value)
} else {
result[key] = value
}
})
return result
}
JSON.parse(JSON.stringify(obj))
const deepClone2 = source => {
const dictionary = {}
const result = {}
const stack = [{ source, result }]
while (stack && stack.length !== 0) {
const { source, result } = stack.shift() // 从头移除一个 或用 pop也行
Object.keys(source).forEach(key => {
const value = source[key]
if (dictionary[key] === value) {
console.error('err 重复引用类型')
return
}
dictionary[key] = value
if (Object.prototype.toString.call(value) === '[object Object]') {
result[key] = {}
stack.push({ source: value, result: result[key] })
} else {
result[key] = value
}
})
}
return result
}
var target = {
a: {
b: {
c: 123
}
},
d: {
e: 456
},
f: 111
}
function deepClone (target) {
var result = {}
var map = new Map()
// [{ key: a, val: { ... }, result }, { key: d, val: { ... }, result }, { key: f, val: 111, result }]
var stack = Object.keys(target).map((key) => ({ key, val: target[key], obj: result }))
while (stack && stack.length > 0) {
var { key, val, obj } = stack.shift()
// 重复引用过滤
if (map.get(key) === val) return
map.set(key, val)
if (Object.prototype.toString.call(val) === '[object Object]') {
var temp = Object.keys(val).map(i => {
obj[key] = {}
return { key: i, val: val[i], obj: obj[key] }
})
stack = stack.concat(temp)
} else {
obj[key] = val
}
}
return result
}
deepClone(target)
class EventEmitter {
constructor () {
this.queueObj = {}
}
on (key, fn) {
if (typeof key !== 'string' && typeof fn !== 'function') {
return
}
if (key in this.queueObj) {
this.queueObj[key].push(fn)
} else {
this.queueObj[key] = [fn]
}
}
emit (key, ...args) {
if (key in this.queueObj) {
this.queueObj[key].forEach((fn) => {
if (args.length > 0) {
fn.apply(this, args)
} else {
fn.call(this)
}
})
} else {
console.error('没有该key值')
}
}
delete (key) {
if (key in this.queueObj) {
delete this.queueObj[key]
}
}
remove (key, fn) {
if (this.queueObj[key]) {
const index = this.queueObj[key].indexOf(fn) // 数组.indexOf(查询内容位置)
if (index > -1) {
this.queueObj[key].splice(index, 1) // splice 删除第index的结点开始 1个
}
}
}
get (key) {
if (key in this.queueObj) {
console.log(this.queueObj[key])
} else {
console.error('error get失败')
}
}
}
const event = new EventEmitter()
event.on('key', function (x) { console.log('x', x) })
event.on('key', function (y) { console.log('y', y) })
event.on('key', function (z) { console.log('z', z) })
event.emit('key', [1, 2, 3])
event.get('key')
/*
instanceObj instanceOf Class 实例对象是否属于某个类
eg: p instanceof Person
instanceObj = new Class()
instanceObj._proto_ = Class.prototype 🔥
Class.prototype.constructor = Class
只需要判断, 实例对象 _proto_ 指针是否指向 类的原型
*/
function _instanceOf (instanceObj, Class) {
const target = Class.prototype
const proto = instanceObj._proto_
while (proto) {
if (proto === target) return true
proto = proto._proto_
}
return false
}
function _new (Class, ...args) {
// 1. 创建对象
const obj = {}
// 2. 公共方法或属性指向
// 或 obj = Object.create(Class.prototype)
obj.__proto__ = Class.prototype
// 3. 私有属性或方法执行
const result = Class.apply(obj, args)
// 4. 如果返回的不是一个对象, 则直接返回obj
return result instanceof Object ? result : obj
}
目的: 在原型链上层 再封装个proto
xxx = {
_proto_: {
prototype
}
}
// Object.create(原型对象) 封装个指针指向目标值
const objectCreate = prototype => {
// 目标 obj._proto_ = prototype
function F () {}
F.prototype = prototype
return new F()
}
1. 构造函数继承
Parent.apply(this, argsArr) 默认返回this
Parent.call(this, a, b, c) 默认返回this
2. 原型方法继承 I
# 本质: 包一层_proto_ 指向公共
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
3. 原型方法继承 II
# 本质: 包一层_proto_ 指向公共
Child.prototype = new Parent()
Child.prototype.constructor = Child
4. ES6
class A extends React.Component {
constructor (props) {
super(...props)
}
}
// 1. 继承构造器里的内容 直接执行Class就行
// 2. 继承原型的方法, 原型链的创建
function Parent (surname, home) {
this.surname = surname
this.home = home
}
Parent.prototype = {
construtor: Parent,
getParent: function () { console.log(this.surname + this.home) }
}
// 🔥 继承构造器内容
function Child (surname, home, givename) {
Parent.call(this, surname, home)
// const args = Array.prototype.slice.call(arguments) 类数组转为数组
// Parent.apply(this, args)
this.givename = givename
}
// 🔥 原型链继承方式 Child.prototype = { _proto_: { Parent.prototype } }
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
Child.prototype.getChild = function () {
console.log(this)
}
// 或者
Child.prototype = new Parent()
Child.prototype.constructor = Child
const child = new Child('林', '中国', '😃')
child.getChild()
child.getParent()
console.log(child instanceof Child)
console.log(child instanceof Parent)
function JSONP (options = {}) {
const { url = '', paramsObj = {}, callbackName = '' } = options
if (typeof(url) !== 'string' || typeof(callbackName) !== 'string') {
console.error('url or callbackName formatting error')
return
}
if (Object.prototype.toString.call(paramsObj) !== '[object Object]') {
console.error('paramsObj formatting error')
return
}
// 处理 paramsObj 重点是这里, 一定要是callback结尾
paramsObj.callback = callbackName
let paramList = []
for (let key in paramsObj) {
const value = paramsObj[key]
paramList.push(key + '=' + value)
}
const paramstr = paramList.join('&')
const reqUrl = url + '?' + paramstr
// 处理标签
const el = document.createElement('script')
el.setAttribute('src', reqUrl)
document.body.appendChild(el)
// 回调处理 🔥
return new Promise((resolve, reject) => {
window[callbackName] = (resp) => {
resolve(resp)
delete window[callbackName]
el.parentNode.removeChild(el)
}
})
}
JSONP({
url: 'http://photo.sina.cn/aj/index',
paramsObj: {
page: 1,
cate: 'recommend'
},
callbackName: 'jsoncallback'
}).then(data => {
console.log(data)
})
const array = [1, [2], [3, [4, [5]]]]
// 拍平
function flatten (array, result = []) {
for (let i = 0; i < array.length; i ++) {
// 递归完成
// Array.isArray(array[i])
if (Object.prototype.toString.call(array[i]) === '[object Array]') {
flatten(array[i], result)
} else {
result.push(array[i])
}
}
return result
}
console.log(flatten(array, []))
// 用reduce实现
function flatten_reduce (array) {
array.reduce((accumulator, current) => {
if (Array.isArray(current)) {
return accumulator.concat(flatten_reduce(current)) // 需要再次递归完成
} else {
return accumulator.concat(array) // 直接连接
}
}, [])
}
flatten_reduce(array)
/**
* 迭代器 Iterator
*
* 本质: 单链表 SingleLinkList
* 引用: Generator -> async await
* 描述: [666, 888, 000]
* 指针默认指向0位置, 当执行 返回 { done: 是否到头标识, value: 当前值 }
* 例如:
* it = iterator([666, 888, 000])
* it.next() // { done: false, value: 666 }
* it.next() // { done: false, value: 888 }
* it.next() // { done: true, value: 000 } / 到头了 不允许再往下了
*/
function _iterator_ (queue) {
let pointer = 0
return {
next: function () {
// 迭代器 到头了
if (pointer === queue.length - 1) {
return { done: true, value: queue[pointer] }
}
pointer ++ // 指针指向
return { done: false, value: queue[pointer - 1] }
}
}
}
let it = _iterator_([666, 888, 000])
console.log(it.next()) // {done: false, value: 666}
console.log(it.next()) // {done: false, value: 888}
console.log(it.next()) // {done: true, value: 0}
Obj.prototype[Symbol.iterator] 原型链上写该方法即可
class Obj {
constructor(value) {
this.value = value
this.next = null
}
// Obj.prototype[Symbol.iterator] 写迭代器方法
[Symbol.iterator] = function () {
let current = this
return {
next: function () {
if (current) {
const value = current.value
current = current.next // 指向下一个指针
return { done: false, value }
}
return { done: true, value: undefined }
}
}
}
}
var one = new Obj(1)
var two = new Obj(2)
var three = new Obj(3)
one.next = two
two.next = three
console.log(one)
for (let p of one) {
console.log(p)
}
good jiayu!
nice jaiyu!
JS 基础
[JS基础] 1 - 内存空间
[JS基础] 2 - 执行上下文
[JS基础] 2.1 - 函数声明 变量声明
[JS基础] 2.2 - 类型及类型判断
[JS基础] 3 - 变量对象 Variable Object
[JS基础] 4 - 作用域与作用域链 scope / scope chain
[JS基础] 5 - 闭包 Closure
[JS基础] 6 - 执行机制, 同步异步, 事件循环, 宏任务, 微任务
[JS基础] 7 - this, call/apply/bind/箭头函数
[JS基础] 8 - 从 Chrome 看 闭包 / this / 作用域链
[JS基础] 9 - 函数式编程 Functional Programming
[JS基础] 10 - 构造函数 原型 原型链 继承 new
[JS基础] 11 - Promise
[JS基础] 12 - 深拷贝 VS 浅拷贝
[JS基础] 13 - 其他 JS 基础
[JS基础] 14 - V8的回收机制 ♻️ / 内存泄露
[JS基础] 15 - 节流 防抖 / Event Bus / new实现