Lambda函数vs绑定,内存! (和表现)

时间:2017-02-08 16:00:47

标签: javascript lambda bind

我想确定哪种是等效解决方案之间的最佳实践。用例是监听事件的类的实例。 Axel Rauschmayer博士prefers the lambda为了便于阅读。我同意他的看法。但就性能和内存消耗而言,这是最好的吗?

使用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中的实施代码。它效率不高。我坚持认为:所有我看到的基准测试,在所有浏览器上显示类似的结果。

有没有办法在同一时间内使用低内存和良好的性能?

1 个答案:

答案 0 :(得分:18)

闭包(或箭头函数,又名 lambdas )不会导致内存泄漏

  

如果垃圾收集器无法清除本地变量(此处el),是否可以确认或确认?或者,现代浏览器是否能够检测到它们在闭包中未被使用?

,现代JavaScript引擎能够检测来自父作用域的变量,这些变量从闭包中可见但未使用。我找到了证明这一点的方法。

步骤1:闭包使用10 MB

的变量

我在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的开发者工具中,选项卡“个人资料”,我带了一个堆快照

Snapshot 1: the variable <code>arr</code> is used in the closure

通过减小大小排序后,第一行是:“system / JSArrayBufferData”,大小为10 MB。这是我们的变量arr

步骤2:10 MB的变量可见但在闭包中未使用

现在我只删除此代码行中的arr参数:

            el.addEventListener("click", ev => this.onClick(ev))

然后,第二个快照:

Snapshot 2: the variable <code>arr</code> is not used in the closure

第一排消失了。

此体验确认垃圾收集器能够清除在活动闭包中可见但未使用的父作用域中的变量。

关于Function.prototype.bind

我引用了Google JavaScript Style Guide关于箭头函数的部分:

  

切勿致电f.bind(this)goog.bind(f, this)(并避免撰写const self = this)。使用箭头功能可以更清楚地表达所有这些并且更不容易出错。这对于回调特别有用,回调有时会传递意外的附加参数。

Google明确建议使用lambdas而不是Function.prototype.bind

相关: