关于JavaScript中for语句的引用问题

原贴

JavaScript,为什么此处没有异步也需要用闭包

今天闲来无事重写了这个方法.大概意思就是根据属性名判断是否是post开头,如果是的话将这个属性对应的方法进行改写,先进行一个随机数判断再决定是否执行原方法。正确的写法是用匿名函数或者let

之前的帖子中如果我舍弃用匿名函数的话(也就是错误写法),只有post3这个属性会被改写,因为ifunc的指向都是最后一次for中i的值,所以被覆盖了。但是这一次我的代码中3个方法都被改写成了post3的方法,obj[i]并没有被覆盖。让我觉得非常疑惑。为什么两次相同的代码结果会不一样。
var obj = {
    post1: function() {
        console.log('post1')
    },
    post2: function() {
        console.log('post2')
    },
    post3: function() {
        console.log('post3')
    },
    check: function() {
        return Math.random() > 0.5
    }
}

function changeFunc(obj){
    for(var i in obj){
        if (i.indexOf('post')==0 && typeof obj[i] == 'function') {
            var func = obj[i]
            obj[i] = function() {
                if (obj.check()) {
                    func.apply(this, arguments)
                }
            }
        }
    }
}
changeFunc(obj)
obj.post1()
obj.post2()
obj.post3()

结果是随机输出0-3个'post3',这是为啥呢= =

阅读 2.2k
2 个回答

闭包与变量提升问题。

function changeFunc(obj){
    for(var i in obj){
        if (i.indexOf('post')==0 && typeof obj[i] == 'function') {
            // =========================
            var func = obj[i]
            obj[i] = function() {
                if (obj.check()) {
                    func.apply(this, arguments)
                }
            }
        }
    }
}

上面代码中变量func使用var定义的,会被提升到函数开头,所以你重写的三个函数都是公用同一个变量func,调用的肯定也是同一个函数,即遍历中最后满足条件的函数。

var改为let就没问题了,let定义的变量不会提升。

典型的变量提升问题。for 循环结束后所有用到的 i 变量都会被替换成最后一次循环的值

如果你把 post2 属性定义在 post3 后面:

{
  post3: Function,
  post2: Function,
}

你看到的结果将是三个 'post2'

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题