javascript
模拟实现
Function.prototype.myBind = function (...args) {
let _this = this
let arr = args.slice(1)
return function F(...params) {
arr = arr.concat(params)
if (this instanceof F) {
return new _this(...arr)
}
return _this.apply(args[0], arr)
}
}
Function.prototype.myCall = function (context, ...args) {
if (context === undefined) {
return this(...args)
}
context = new Object(context)
context.fn = this
let res = context.fn(...args)
delete context.fn
return res
}
Function.prototype.myApply = function (context, args) {
if (context === undefined) {
return this(...args)
}
context = new Object(context)
context.fn = this
let res = context.fn(...args)
delete context.fn
return res
}
function myNew (F, ...args) {
let obj = {}
obj.__proto__ = F.prototype
let res = F.apply(obj, args)
return typeof res==='object' and typeof res !== null ? res : obj
}
理论
- Object.prototype.toString.call 是如何判断变量的类型的,讲原理
- JavaScript的垃圾回收机制是怎样的,简述一下
- 标记清除法
- 垃圾收集器找到所有的根,并“标记”(记住)它们。
- 然后它遍历并“标记”来自它们的所有引用。
- 然后它遍历标记的对象并标记 它们的 引用。所有被遍历到的对象都会被记住,以免将来再次遍历到同一个对象。
- 直到所有可达的(从根部)引用都被访问到。
- 没有被标记的对象都会被删除。
- 什么是强引用与弱引用
- 拥有强引用的数据不会被垃圾回收机制回收
- 拥有弱引用的数据,不计入垃圾回收机制
- Map与WeakMap的区别有哪些
- MAP
- MAP 可以接受各种类型的数据作为键
- MAP 对数据的引用是强引用
- WeakMap
- WeakMap 只能接受对象作为键名(不包括null)
- WeakMap 对数据的引用是弱引用
- 一旦消除对键的引用,它占用的内存就会被垃圾回收机制释放
- WeakMap 有助于防止内存泄漏
- null 与 undefined 有什么区别
- null
- null 表示空值
- typeof null === 'object'
- JSON.Stringify 不会 省略值为null的属性
- undefined
- undefined 表示当前变量未被赋值、参数未传递、函数无返回值
- typeof undefined === 'undefined'
- JSON.Stringify 会 省略值为undefined的属性
- 常见的内存泄露场景有哪些,如何避免
- 全局变量
- 当全局变量不需要时,及时释放引用
- 尽量少用全局变量
- 事件绑定
- 当在 DOM 上绑定事件时,如果 DOM 元素被移除,事件仍然存在(现代浏览器不存在这样的问题)
- 移除 DOM 元素时,一同移除事件
- DOM 引用
- 当引用的 DOM 元素在文档中被移除时,引用就无意义了,应该及时释放引用
- 定时器
- 假如对某个 DOM 元素 绑定了定时器事件,如果该 DOM 元素被移除,那么定时器也应该及时释放
场景
- 请求合并:短时间内需要请求多个资源合并成一个请求发送
const demoRes = {
1:{
data:{}
},
2:{
data:{}
}
}
request({
url:'/path',
query:{
id:''
}
})
getArticle(3).then(res=>{})
getArticle(4).then(res=>{})
getArticle(5).then(res=>{})
getArticle(6).then(res=>{})
function request(options) {
const { query: { id } } = options
return new Promise((resolve, rej) => {
const res = id.split(',').reduce((pre, _id) => {
pre[_id] = {
data: {
id: _id,
date: new Date().toLocaleString()
}
}
return pre
}, {})
setTimeout(() => {
resolve(res)
}, 2000)
})
}
const getArticle = (() => {
let timer = null
let ids = []
let resolves = {}
return function (id) {
return new Promise((resolve, rej) => {
resolves[id] = !resolves[id] ? [resolve] : resolves[id].concat(resolve)
ids.push(id)
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
const _resolves = resolves
request({
path: '/path',
query: {
id: [...new Set(ids)].join(',')
}
}).then(res => {
Object.keys(res).forEach(k => {
_resolves[k].forEach(rl => {
rl((res[k]))
})
})
})
timer = null
ids = []
resolves = {}
}, 0)
})
}
})()