ES5中模仿块级作用域

有一定JavaScript开发经验的人应该会熟悉下面这种立即执行函数的写法:

(function(name){
  console.log('hello ' + name);// hello Bob
})('Bob');

不过即使不熟悉也没关系,这里我会讲解这种写法的含义。

先来看下面这个更容易理解的示例:

var sayHello = function(name){
  console.log('hello ' + name);
}
var name = 'Bob';
sayHello(name);// hello Bob

首先使用函数表达式的语法定义函数sayHello,然后声明一个变量name,紧接着调用sayHello,参数为name

由于变量name没有在其他地方被使用,这里其实也就没有必要声明,可以使用更简便的语法,直接把值传递给函数:

sayHello('Bob');// hello Bob

按照这种逻辑,假如sayHello也是只执行一次,sayHello(name)不是也可以写成下面这种形式吗?

function(name){
  console.log('hello ' + name)
}('Bob');
//Uncaught SyntaxError: Unexpected token (

但是运行发现报错了,这是因为JavaScript将function关键字当作一个函数声明的开始,而函数声明的后面是不能跟圆括号的。不过,函数表达式的后面可以跟圆括号,要将函数声明转换成函数表达式,只要像下面这样给它加上一对圆括号即可:

(function(name){
  console.log('hello ' + name);// hello Bob
})('Bob');

也就是本文开头的立即执行函数,模仿块级作用域正是通过立即执行函数实现的。

来看下面的示例:

function outputNumbers(count){
  for(var i = 0; i < count; ++i){
    console.log(i);
  }
  console.log(i);// 5
}
outputNumbers(5);

在Java、C++等语言中,变量i只会在for循环的语句块中有定义,循环一旦结束,变量i就会被销毁。可是在JavaScript中,作用域只分为全局作用域和函数作用域,函数内部声明的变量是绑定在函数作用域对应的变量对象上的,也就是说这里的i是定义在函数的变量对象上的,在函数内部的任何位置都可以访问它,即使for循环结束,i依然存在。

但是如果用立即执行函数包裹for循环,情况就不一样了:

function outputNumbers(count){
  (function(){
    for(var i = 0; i < count; ++i){
      console.log(i);
    }  
  })();
  console.log(i);//Uncaught ReferenceError: i is not defined
}
outputNumbers(5);

此时i绑定在内部立即执行函数的变量对象上,立即执行函数执行完毕就会销毁,i也会随之销毁。根据闭包机制,内部的立即执行函数也可以访问到count。这样就实现了块级作用域——无论在立即执行函数中声明什么变量都不会影响外部变量的使用。

这种技术也经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数,避免冲突,例如:

(function(){
  var now = new Date();
  if(now.getMonth() == 0 && now.getDate() == 1){
    console.log('Happy new year!');
  }
})();

这段代码放在任何全局作用域中都可以在1月1日向用户显示祝贺新年的消息,不必担心全局作用域中是否定义了now变量,从而引起变量的覆盖等问题。

转载于:https://my.oschina.net/bob1900/blog/3043173

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值