这是js闭包问题吗?

发布于 2022-09-06 09:08:23 字数 126 浏览 15 评论 0

图片描述

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

離殇 2022-09-13 09:08:23
this.value; // 试试
萌化 2022-09-13 09:08:23

题主的 for 循环跑完后,实际上:

i=5
btn = 最后一个 input

为什么这样呢,我们来看下代码,稍微改了下:

for(var i=0;i<5;i++){
    var btn=document.createElement('input');
    btn.setAttribute('type','button');
    btn.setAttribute('value','btn'+i);
    document.body.insertBefore(btn,document.body.firstElementChild); //直接插入到文档最前面,方便测试
    btn.onclick=function(){
        alert(btn.value);
    };
}

要知道 es6 之前是没有块级作用域的,且

用 var 定义的变量会有一个声明提升的特性,这个动作开始于代码执行之前,会将 var 定义的变量提升到所在函数或全局环境的顶端,但是赋值操作仍然停留在原地

题主的代码其实相当于:

var i,btn;
for(i=0;i<5;i++){
    btn=document.createElement('input');
    btn.setAttribute('type','button');
    btn.setAttribute('value','btn'+i);
    document.body.insertBefore(btn,document.body.firstElementChild);
    btn.onclick=function(){
        alert(btn.value);
    };
}
console.log(btn); // btn 被赋值了5次,覆盖了4次,最后一个是 btn4,所以很显然是最后一个
console.log(i);  // i=5的时候跳出循环,所以 i 最后一个值是 5

这样是不是就很好理解了?

因为你给 btn 绑定的事件处理程序(回调函数)并不是马上执行,触发的时候才执行,这个时候 btn 已经被覆盖了4次,变成最后一个 btn 了;

核心原因是: var 有声明提前的特性。如要改的话,有多种方式,这里暂就说两种:
法一:btn 改为 this (推荐)

for(var i=0;i<5;i++){
    var btn=document.createElement('input');
    btn.setAttribute('type','button');
    btn.setAttribute('value','btn'+i);
    document.body.insertBefore(btn,document.body.firstElementChild);
    btn.onclick=function(){
        alert(this.value);
    };
}

在事件绑定中,如果事件处理程序(也就是回调函数)中没有嵌套的函数,事件绑定在谁身上,this 就指向谁,如果回调里还有嵌套函数,this 默认指向全局对象,所以这里 this 就指向了绑定时的那个 btn;不明白戳这
法二:用 let 代替 var

for(var i=0;i<5;i++){
    let btn=document.createElement('input');
    btn.setAttribute('type','button');
    btn.setAttribute('value','btn'+i);
    document.body.insertBefore(btn,document.body.firstElementChild);
    btn.onclick=function(){
        alert(btn.value);
    };
}

这是 ES6 的内容,详细理解戳这:深入理解ES6-中

酒解孤独 2022-09-13 09:08:23

因为你每次for循环的时候,给按钮添加了点击事件,同时btn也会指向不同的按钮,在最后一次循环的时候,btn指向了最后一个按钮,所以每次输出的都是4

你的笑 2022-09-13 09:08:23

或许你可以把里面的点击事件包成匿名函数自执行然后传参,也可以应用ES6里面的let 声明循环变量,因为在每一个{}中都是一个let作用域

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文