Js 闭包、定时器

问题

什么是闭包? 有什么作用

闭包可以用来读取函数内部的变量。

function f1() {
  var n = 999;
  function f2() {
    console.log(n);
  }
  return f2;
}

var result = f1();
result(); //999

由于作用域链表,外部是无法读取到函数内部的变量的。所以如果想要得到函数内部的变量,可以在函数体内部再定义一个函数,这个用这个函数返回所需要的变量。

function create_counter(initial) { 
    var x = initial || 0; 
    return { inc: function () { 
    x += 1; 
    return x; 
    } 
}}

var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3

var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13
  • 上面例子中,c1,c2引用的外部函数的x,是独立的两个值,封闭的包装。
  • 闭包可以理解为是携带状态的函数,并且它的状态可以完全对外隐藏起来。

setTimeout 0 有什么作用

setTimeout(f, 0) ; 将第二个参数设为 0,作用是让 f 在现有的任务(脚本的同步任务和“消息队列”指定的任务)一结束就立刻执行。也就是说,setTimeout(f, 0)的作用是,尽可能早地执行指定的任务,而并不是会立刻就执行这个任务。

  • 可以用于调整事件的发生顺序;
  • 将一些消耗性能的任务,分成小块放到setTimeout(f, 0)中,可以减轻性能压力。

代码题

下面的代码输出多少?修改代码让fnArr[i]()输出 i。使用两种以上的方法

    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
        fnArr[i] =  function(){
            return i;
        };
    }
    console.log( fnArr[3]() );  //10

这段代码输出10。上段循环中,将一个函数,依次写进一个数组中,而这个函数不是立即执行的,通过fnArr[]()调用,才进行执行。所以当循环结束后,此时i的数值已经变化为10,当调用fnArr[3](),实际上执行的是return i ; ,而此时的 i 就是 10。

    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
        fnArr[i] =  (function (n){
          return function (){
             return n;
          };
        })(i);
    }
    console.log( fnArr[3]() ); //3
    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
        fnArr[i] =  function fn(){
            return fn.id;
        };
        fnArr[i].id = i;
    }
    console.log( fnArr[5]() );  //5

使用闭包封装一个汽车对象,可以通过如下方式获取汽车状态

function car(){
  var speed = 0;
  return {
    setSpeed:function(val){
      speed = val;
      return speed;
    },
    getSpeed:function(){
      console.log(speed);
      return speed;
    },
    accelerate:function(){
      speed += 10;
    },
    decelerate:function(){
      speed -= 10;
      if (speed < 0){
        speed = 0;
      } 
    },
    getStatus:function(){
      if(speed!==0){
        console.log('running');
        return 'running';
      }
      else {
        console.log('stoped');
        return 'stoped';
      }
    }
  };
}

var Car = car();

Car.setSpeed(30);
Car.getSpeed(); //30
Car.accelerate();
Car.getSpeed(); //40;
Car.decelerate();
Car.decelerate();
Car.getSpeed(); //20
Car.getStatus(); // 'running';
Car.decelerate(); 
Car.decelerate();
Car.getStatus();  //'stop';
//Car.speed;  //undefined;

写一个函数使用setTimeout模拟setInterval的功能

var i = 0;
function interval(){
  setTimeout(function(){
    console.log(i++);
    interval();
  },1000);
}
interval();

写一个函数,计算setTimeout最小时间粒度

function getMini(){
  var i = 0;
  var start = Date.now();
  var timer = setTimeout(function(){
    i++;
    if(i === 1000){
      clearTimeout(timer);
      var end = Date.now();
      console.log((end-start)/i);
    }
    timer = setTimeout(arguments.callee,0);
  },0);
}
getMini();//4.112//4.117

下面这段代码输出结果是? 为什么?

var a = 1;
setTimeout(function(){
    a = 2;
    console.log(a);//3执行
}, 0);
var a ;
console.log(a);  //1执行
a = 3;
console.log(a);//2执行
//1  3  2
  • setTimeout(func,0) 会将任务在下一个Event Loop之前执行,所以这里的function被移到了最后进行执行。

下面这段代码输出结果是? 为什么?

var flag = true;
setTimeout(function(){
    flag = false;
},0);//理论上不会执行
while(flag){}
console.log(flag);//理论上不会执行
Js 闭包、定时器_第1张图片
  • setTimeout将function移到下一个Event Loop之前执行,但是while将这个阻断了,陷入了无限循环。所以flag不能被赋值成false。这也说明程序的运行是单线程的。

下面这段代码输出?如何输出delayer: 0, delayer:1...(使用闭包来实现)

for(var i=0;i<5;i++){
    setTimeout(function(){
         console.log('delayer:' + i );
    }, 0);
    console.log(i);
}
-----------
for(var i=0;i<5;i++){
    (function(num){
      setTimeout(function(){
         console.log('delayer:' + num );
    }, 0);
    })(i);
    console.log(i);
}

本教程版权归 张宇 及 饥人谷 所有,转载请标明出处。

你可能感兴趣的:(Js 闭包、定时器)