资讯专栏INFORMATION COLUMN

ES5和ES6作用域详解

sourcenode / 2580人阅读

摘要:函数作用域虽然不存在真正意义上的块级作用域,但是存在函数作用域,为了解决上述伪块级作用域的问题,使用函数解决法如下结果为结果为注意以上生成函数作用域的写法存在两个问题,第一申明了全局的具名函数,污染了全局作用域。

ES5和ES6作用域 ES5的块级作用域 ES5的块级作用域是一个伪块级作用域,代码块:{},它的块里面和块外面都是共用一个作用域,即:

Example:

{
    var a =3;
    console.log(a); //结果为3   
}
console.log(a); //结果为3

Example:
ES5的伪块级作用域另外一个典型的例子如下:

var a = [];
for(var i=0;i<10;i++){
    a.push(function(){
        console.log(i);
    });
}
a[0](); //预期结果是0,实际结果是10

注意:出现上述现象的主要原因是使用var定义的变量 i 是一个全局变量,导致真正在调用的时候虽然循环了10次,可是最终十次都是只修改了全局变量 i ,并没有区分出私有作用域。与之相反的两个例子如下:

Example1: 这个是利用ES6的let申明的变量会限制在当前块级作用域内,每次重新申明了变量,申明了10次

var a =[];
for(let i=0;i<10;i++){
    a.push(function(){
        console.log(i);
    });
}
a[0](); //结果为10

Example2: 这个是利用构建闭包来生成私有作用域

var a = [];
for(var i=0;i<10;i++){
    a.push((function($i){//$i是该匿名函数的入参,等同下面的i
        function k(){
            console.log($i);
        }
        return  k;
    })(i));
}
a[0](); //结果为0

注意:如果上面的Example2不使用参数传递的方式创建私有作用域,那也可以内部定义变量的方式来代替,值得注意的是如果是直接引用外部变量创建的结果最终是一个空作用域,并不能达到隔变量 i 的效果
Example3:错误例子

var a = [];
for(var i=0;i<10;i++){
    a.push((function(){//$i是该匿名函数的入参,等同下面的i
        function k(){
            console.log(i);
        }
        return  k;
    })());
}
a[0](); //结果为10
ES5中的块级作用域有效的只有try catch,如:

Example:

try{
    throw 3;
}catch(e){
    console.log(e); //结果为3
}
console.log(e); //结果为ReferenceError

注意:正因为try catch有如上的功能,所以有时候有些框架为了区分块级 私有 作用域就是用它来解决的,例如google的Traceur项目。

综上所述:ES5伪块级作用域的问题是没有创建私有作用域,污染了它的父级甚至可能是全局作用域覆盖window对象的原生方法或属性。

ES5函数作用域

ES5虽然不存在真正意义上的块级作用域,但是存在函数作用域,为了解决上述ES5伪块级作用域的问题,使用函数解决法如下:
Exapmle1

var a = 1;
function fun(){
    var a = 5;
    console.log(a); //结果为5
}
fun();
console.log(a); //结果为1

注意:以上生成函数作用域的写法存在两个问题,第一:申明了全局的具名函数fun,污染了全局作用域。第二:如果要实现这个私有作用域,必须要函数调用才行。

Example2:改良上述两个问题的写法如下:

var a = 1;
(function (){
    var a =5;
    console.log(a); //结果为5
})();
console.log(a); //结果为1

注意:例子2的写法在JS社区规定的术语是立即执行函数表达式——IIFE,它可以无伤地创建一个块级私有作用域替代ES5的伪块级作用域,还有虽然它般用和闭包结合使用,但注意和闭包的区分。

立即执行函数表达式另一个常用技巧

倒置立即执行函数代码的运行顺序,将需要运行的函数放在第二位,在立即执行函数执行之后当作参数传递进去。这种模式在UMD(Universal Module Definition)项目中被广泛使用。

Example

var a=2;
(function IIFE( def ){ 
    def( window );
})(function def( global ) {
    var a=3;
    console.log( a ); // 3  
    console.log(global.a); //2
});

代码解读:例子中将代码主体放在了立即执行函数的参数部分,当做参数传递给执行函数,执行函数的内部又立即调用了这个函数,并将全局的window对象当做参数传递给参数主体函数,并匿名window为global来调动全局a变量,达到不会与参数主体函数的作用域冲突。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/83985.html

相关文章

  • ES5ES6作用详解

    摘要:允许在块级作用域内声明函数。上面代码中,存在全局变量,但是块级作用域内又声明了一个局部变量,导致后者绑定这个块级作用域,所以在声明变量前,对赋值会报错。 ES5的作用域 变量起作用的范围,js中能创建作用域的只能是函数 { let a = 1; var b = 2; } console.log(a); // a is not defined console.log(b); //...

    Dr_Noooo 评论0 收藏0
  • ES5ES6数组遍历方法详解

    摘要:和数组遍历方法详解在中常用的种数组遍历方法原始的循环语句数组对象内置方法数组对象内置方法数组对象内置方法数组对象内置方法数组对象内置方法数组对象内置方法数组对象内置方法数组对象内置方法循环语句中新增加了一种循环语句三种数组循环示例如下原始循 ES5和ES6数组遍历方法详解 在ES5中常用的10种数组遍历方法: 1、原始的for循环语句2、Array.prototype.forEach数...

    GitChat 评论0 收藏0
  • ES6 变量作用与提升:变量的生命周期详解

    摘要:不同的是函数体并不会再被提升至函数作用域头部,而仅会被提升到块级作用域头部避免全局变量在计算机编程中,全局变量指的是在所有作用域中都能访问的变量。 ES6 变量作用域与提升:变量的生命周期详解从属于笔者的现代 JavaScript 开发:语法基础与实践技巧系列文章。本文详细讨论了 JavaScript 中作用域、执行上下文、不同作用域下变量提升与函数提升的表现、顶层对象以及如何避免创建...

    lmxdawn 评论0 收藏0
  • JavaScript声明变量详解

    摘要:命令用于规定模块的对外接口,命令用于输入其他模块提供的功能所以在一定程度上来说,也具有声明变量的功能。当没有声明,直接给变量赋值时,会隐式地给变量声明,此时这个变量作为全局变量存在。 前言 如果文章中有出现纰漏、错误之处,还请看到的小伙伴多多指教,先行谢过 在ES5阶段,JavaScript 使用 var 和 function 来声明变量, ES6 中又添加了let、const、imp...

    paulquei 评论0 收藏0
  • [面试专题]ES6之箭头函数详解

    摘要:使用或调用由于已经在词法层面完成了绑定,通过或方法调用一个函数时,只是传入了参数而已,对并没有什么影响箭头函数不会在其内部暴露出参数等等,都不会指向箭头函数的,而是指向了箭头函数所在作用域的一个名为的值如果有的话,否则,就是。 ES6之箭头函数 标签(空格分隔): 未分类 返回值 单行函数体默认返回改行计算结果, 多行需要指定返回值 let c = (a,b)=>a+b; conso...

    Caicloud 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<