因一段JavaScript代码引发的闲扯

页面导航:首页 > 网络编程 > JavaScript > 因一段JavaScript代码引发的闲扯

因一段JavaScript代码引发的闲扯

来源: 作者: 时间:2016-02-02 09:58 【

前两天,一朋友给我发了一段JavaScript代码: function f1(){ var n=999; nAdd=function(){ n+=1 }; function f2(){ alert(n); }

前两天,一朋友给我发了一段JavaScript代码:

  function f1(){
    var n=999;
    nAdd=function(){
        n+=1
    };
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result1=f1();
    var result2=f1();
  result1(); // 999
    result2();//999
  nAdd();
   result1(); // 是999而不是1000,这是为何呢?
    result2();//1000

问题的原型在这里:javascript关于闭包的面试题
这里主要利用两个知识点:声明提升闭包
在JavaScript中,没有用var关键字声明的变量均是隐式的全局变量。首先将全局变量声明提前,代码是这样子:

  var nAdd = undefined;
  function f1(){
    var n=999;
    nAdd=function(){
        n+=1
    };
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result1=f1();
    var result2=f1();
  result1(); // 999
    result2();//999
  nAdd();
   result1(); // 是999而不是1000,这是为何呢?
    result2();//1000

然后根据个人理解来解释一下原因:

var result1=f1();
var result2=f1();

这里两次调用f1(),因返回的f2起到了闭包的作用,因而result1result2都各自保存对n的引用,但是nAdd被赋值了两次,后一次赋值覆盖了前一次的值。为了便于解释,引入两个临时变量,当第一次调用f1时,代码是这样子的:

 function f1(){
    var n=999;
    //n在result1中的引用为temp1
    var temp1 = n;
    nAdd=function(){
        temp1 += 1;
    };
    function f2(){
      alert(temp1);
    }
    return f2;
  }

第二次调用f1时,代码应该是这样子的:

function f1(){
    var n=999;
     //n在result2中的引用为temp2
    var temp2 = n;
    nAdd=function(){
        temp2 += 1;
    };
    function f2(){
      alert(temp2);
    }
    return f2;
  }

所以当调用nAdd()时,只影响result2n的值,对result1中的n没有影响。在后面再对result1result2追加一次调用,结果应该是这样子的:

    var result1=f1();
    var result2=f1();
  result1(); // 999
    result2();//999
  nAdd();
   result1(); // 999
    result2();//1000
    result1(); // 999
    result2();//1001

问题就解释到这里。如果你有其它理解,欢迎留下评论。

查找了关于声明提升和闭包的文章,除了扯一下这两点,也一并扯扯JavaScript中的回调函数、作用域和IIFEs(Immediately-Invoked Function Expressions)。

声明提升(Hoisting)

对于变量声明或函数表达式。可以看作由两部分组成:声明和赋值。JavaScript隐式地提升声明部分到封闭函数的顶部,而将赋值留在原地。需要注意的一点是:变量和函数声明存在此特征,但是函数表达式是没有这个特征的。看几段代码就知道这是怎么一回事了。

var x= 0;
var f=function(){
    x=1;
};
f();
alert(x); 
function f(){
    x = 2;
}
f();
alert(x);

猜猜上面的结果是什么?看看下面的等效代码,来校验一下你猜的答案:

var x;
var y;
function f(){
    x = 2;
}
x = 0;
f = function(){
    x = 1;
}
f();
alert(x); 
f();
alert(x);

两次弹出的结果都是1,你猜对了吗?
再举两个简单的例子来分别说明一下变量声明提升和函数声明提升。

(function() {
  var foo = 1;
  alert(foo +   + bar +   + baz);
  var bar = 2;
  var baz = 3;
})();

能猜出结果吗?看看下面的等效代码,来校验一下你猜的答案:

(function() {
  var foo;
  var bar;
  var baz;

  foo = 1;
  alert(foo +   + bar +   + baz);
  bar = 2;
  baz = 3;
})();

所以结果是1undefinedundefined
函数声明提前的好处是可以提前调用要定义的函数:

foo();
function foo() {
  alert(Hello!);
}
//其等效的代码
function foo() {
  alert(Hello!);
}
foo();

正如之前所说的,函数表达式是没有声明提前的,所以按上述方式调用会出错:

foo();    //undefined is not a function
var foo = function() {
  alert(Hello!);
};

闭包

闭包是JavaScript最优雅、最具表现力的特性之一。创建闭包的两种常见方式:
1、将内部函数作为值从外部函数返回

function B()
{
    var temp=abc;
    function A()
    {
        alert(闭包函数处理本地变量temp = +temp);
    }
    return A;
    //或者直接返回
    //return functio()
    //{
    //  alert(闭包函数处理本地变量temp = +temp);
    /
                 
                
Tags:

文章评论


<