我想确定哪种是等效解决方案之间的最佳实践。用例是监听事件的类的实例。 Axel Rauschmayer博士prefers the lambda为了便于阅读。我同意他的看法。但就性能和内存消耗而言,这是最好的吗?
class Abc {
constructor() {
let el = document.getElementById("my-btn")
if (el)
el.addEventListener("click", evt => this.onClick(evt))
}
onClick(evt) {
console.log("Clicked!", evt.target)
}
}
如果垃圾收集器无法清除本地变量(此处el
),是否可以确认或确认?或者,现代浏览器是否能够检测到它们在闭包中未被使用?
Function.prototype.bind
:class Abc {
constructor() {
let el = document.getElementById("my-btn")
if (el)
el.addEventListener("click", this.onClick.bind(this))
}
onClick(evt) {
console.log("Clicked!", evt.target)
}
}
没有内存问题,但所有基准测试表明bind
远比闭包慢(例如here)。
编辑:我不同意忽略bind
的效果问题的评论。我建议您阅读this answer以及Chrome中的实施代码。它效率不高。我坚持认为:所有我看到的基准测试,在所有浏览器上显示类似的结果。
有没有办法在同一时间内使用低内存和良好的性能?
答案 0 :(得分:18)
如果垃圾收集器无法清除本地变量(此处
el
),是否可以确认或确认?或者,现代浏览器是否能够检测到它们在闭包中未被使用?
是,现代JavaScript引擎能够检测来自父作用域的变量,这些变量从闭包中可见但未使用。我找到了证明这一点的方法。
我在Chromium中使用了这段代码:
class Abc {
constructor() {
let arr = new Uint8Array(1024*1024*10) // 10 MB
let el = document.getElementById("my-btn")
if (el)
el.addEventListener("click", ev => this.onClick(ev, arr))
}
onClick(ev) {
console.log("Clicked!", ev.target)
}
}
new Abc()
请注意arr
类型的变量Uint8Array
。它是typed array,大小为10兆字节。在第一个版本中,变量arr
用于闭包。
然后,在Chromium的开发者工具中,选项卡“个人资料”,我带了一个堆快照:
通过减小大小排序后,第一行是:“system / JSArrayBufferData”,大小为10 MB。这是我们的变量arr
。
现在我只删除此代码行中的arr
参数:
el.addEventListener("click", ev => this.onClick(ev))
然后,第二个快照:
第一排消失了。
此体验确认垃圾收集器能够清除在活动闭包中可见但未使用的父作用域中的变量。
Function.prototype.bind
我引用了Google JavaScript Style Guide关于箭头函数的部分:
切勿致电
f.bind(this)
或goog.bind(f, this)
(并避免撰写const self = this
)。使用箭头功能可以更清楚地表达所有这些并且更不容易出错。这对于回调特别有用,回调有时会传递意外的附加参数。
Google明确建议使用lambdas而不是Function.prototype.bind
。
相关: