为了性能优化, 应该用临时变量保存对象的属性以避免多次访问, 那是否也应该用一个变量保存外层作用域的变量呢?

很多教材都说了, 访问属性速度很慢, 所以如果访问一个属性超过一次, 就该用一个临时变量保存该属性, 以避免多次进行属性查找。但是少有教材提到, 访问外层变量的速度如何。
是因为访问外层作用域的速度衰减可以忽略不计, 以至于即便是访问全局作用域的变量, 也比访问一个当前作用域对象的属性还要快, 所以教材才没有对此进行说明吗?
我个人认为应该不是这样的, 访问外层作用域的变量, 其复杂度也是随着作用域的增加而增加的, 所以其复杂度应该也是O(n), 跟访问对象的属性复杂度应该是相同的才对, 既然提到了要用变量保存对象的属性, 那理应也提一提用变量保存外部变量吧。
除非我的推测是错误的。请教大神讲解一下访问外层变量的详细机制。

阅读 2.4k
3 个回答

专业的回答我没有,但是我开发中会这样处理:


let a = pts.c.d.e.qqq
let b = pts.c.d.e.fff

当我有这样的访问时,我就会改成下面的

let pts_e = pts.c.d.e

let a = pts_e.qqq
let b = pts_e.fff

我并不知道这样能提高效率,我甚至担心会增加内存使用。但这样确实让代码更容易读,更容易改bug
这个处理思路在小学叫提取公因数

无责任瞎猜,具体实现不详。
我们抽象每个函数都有一个隐藏的属性,由于“持有”自身执行所需的上下文。那么假设有如下场景:

function a() {
    let aa = 'aa'
    return function b() {
        let bb = 'bb'
        return function c(cc) {
            console.log(aa + bb + cc)
        }
    }
}

从的角度来看,aa是a的aa,bb是a的b的bb,看起来有点儿嵌套的意思了。c有一个隐藏的属性,就当是这样的:

context = {
    aa: a.aa,
    bb: a.b.bb,
    cc: cc
}

不严谨也不准确哈

那么当c执行的时候,有没有可能函数体内的aa和bb其实就是a.aa和a.b.bb的替身,也就是一个访问器的临时变量。

这只是一种满足“避免多次访问”的自洽的说法。并不是真实的情况。

如果你指的是这种a和b谁访问更快的话,那基本上无论嵌套了多少层a和b的访问速度都是一样的,应为只要在同一个栈帧内的变量他们他们访问方式都是一样的,无非是a和b存储的相对于栈帧开始位置的偏移量不同而已

{
   const a = 3
   {
      {
          const b = 4
          console.log(a)
          console.log(b)
      }
   }
}

如果你指的是跨栈帧的外层变量访问的话比如(你可以认为最外层的代码会被包在一个隐形的函数中,他也有自己的栈帧), 此时就要分开讨论了可以确定的是b的访问速度肯定会大于等于a的访问速度, 考虑在main中使用a的全过程中a都没有离开作用域的风险(要是有离开的风险的话就必须将a复制到main的闭包结构中仅供main内部使用), 此时a在栈上的位置是确定的所以可以优化a的访问速度和b访问速度一致,要是a会离开外部的作用域会被main的闭包捕获的话,此时访问a的速度就变成了获取一个闭包变量的速度,这个也不会慢到哪里去,不过肯定会比直接访问栈变量慢一点

const a = 3
function main() {
    const b = 4
    console.log(a)
    console.log(b)
}
main()
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题