js常见面试题

代码1

 <ul>
    <li class="item">1</li>
    <li class="item">2</li>
    <li class="item">3</li>
    <li class="item">4</li>
    <li class="item">5</li>
  </ul>

// 有5个li标签
var items = document.querySelectorAll('li');

for (var i = 0; i < items.length; i++) {
  items[i].onclick = function(){
    console.log(i);
  };
}

分析上面代码,依次点击li会输出什么?
答案:不管点击哪个li,都输出5
分析之前,需要明确的几个知识点

  • 首先,牢记:js中只有全局作用域函数作用域
  • 其次:牢记:变量的生命周期,分为三种情况,
    • 对于全局变量而言,当页面被刷新或被关闭时,它就死了,也就是其所占的内存被释放;
    • 对于函数内的局部变量(不考虑闭包),退出函数时,它就死了,也就是其占用的内存被释放;
    • 对于函数内的局部变量(考虑闭包),当被返回的函数引用了局部变量,则只有引用该返回函数的变量被回收,局部变量才会被回收。

分析代码:

  • var i 是全局变量
  • 当for循环中给每个li添加了onclick的事件处理函数,注意:事件处理函数并未运行,所以当for执行完毕后,其实i并未被释放,i的值为5
  • 当点击每个li时,调用的i还是原来那个i,也就是5, 所以不管点击哪个li,都打印出5

代码2

function outerFn() {
    console.log("Outer function");
    function innerFn() {
        var innerVar = 0;
        innerVar++;
        console.log("Inner function\t");
        console.log("innerVar = "+innerVar+"");
    }
    return innerFn;
}

var fnRef = outerFn();
fnRef();
fnRef();
 

以上代码都输出:1
因为函数作用域的关系,每调用依次fnRef(),都将生成新的innverVar

改进

function outerFn() {
    var outerVar = 0;
    console.log("Outer function");
    function innerFn() {
        outerVar++;
        console.log("Inner function\t");
        console.log("outerVar = " + outerVar + "");
    }
    return innerFn;
}

var fnRef = outerFn();
fnRef();
fnRef();

var fnRef2 = outerFn();
fnRef2();
fnRef2();

输出: 1, 2,1, 2
var fnRef = outerFn(); 生成了outerVar变量,每次调用fnRef()时,获取的还是原来的那个outerVar;
var fnRef2 = outerFn(); 生成了另一个outerVar变量,这个变量与fnRef中的是不同的,因为它们处于不同的作用域

再次改进

function outerFn() {
    var outerVar = 0;
    function innerFn1() {
        outerVar++;
        console.log( outerVar);
    }

    function innerFn2() {
        outerVar += 2;
        console.log(outerVar);
    }
    return { "fn1": innerFn1, "fn2": innerFn2 };
}

var fnRef = outerFn();
fnRef.fn1();
fnRef.fn2();
fnRef.fn1();

输出: 1, 3, 4
当调用var fnRef = outerFn() 时,可以理解为“创建了一个属于fnRef执行环境”,之后访问的fnRef.fn1(); fnRef.fn2();均是在该执行环境下执行的

回到代码1,如何修改代码,能够实现点击li,打印出正确的数字呢?只需要为每一个li,创造出属于他们自己的独立的i,这个i与for循环中的i,是不同的i,也就是为每个li创造一个独立的执行环境,在js中只有通过函数能够创造一个独立的执行环境(也可以说是作用域),这时候,需要用到闭包来实现,代码如下:

var items = document.querySelectorAll('li');
for (var i = 0; i < items.length; i++) {
  items[i].onclick = (function(i){
    return function(){
      console.log(i);
    };
  })(i);
}

几个知识点:

  • 立即执行函数:为什么使用立即执行函数?因为我们需要将i传进去
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1.基本数据类型有哪些? Undefined、Null、Boolean、Number、String 2.原型,原型...
    hahaland阅读 773评论 1 7
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 34,015评论 18 399
  • 总结了一些常见的js面试题,欢迎大家评论补充。!!!注意不要一味的死记硬背,掌握原理才是关键。 数组去重 var ...
    摄影狗杨木木阅读 939评论 0 15
  • 仇家追杀半月,强弩之末的他立于湖边,苦笑叹自己命数已尽, 湖心白雾绵绵,忽现有少年泛舟垂钓,身披一件白色羽衣,盘膝...
    我跟你去二次元阅读 379评论 2 3
  • 一、iOS 10 隐私权限配置 在iOS 10中,访问隐私权限需要在info.plist文件中进行配置,否则会崩溃...
    X先生_vip阅读 7,166评论 4 3

友情链接更多精彩内容