资讯专栏INFORMATION COLUMN

es6学习笔记-let,const和块级作用域_v1.0_byKL

Youngdze / 1624人阅读

摘要:考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。函数声明语句函数表达式循环循环还有一个特别之处,就是循环语句部分是一个父作用域,而循环体内部是一个多带带的子作用域。声明一个只读的常量。

es6学习笔记-let,const和块级作用域_v1.0 块级作用域

javascript 原来是没有块级作用域的,只有全局作用域和函数作用域

例子1

因为没有块级作用域,所以每次的i都是一样

var a = []; 
for (var i = 0; i < 10; i++) {//变量i是var声明的,在全局范围内都有效
    a[i] = function () {
        console.log(i); //每次的i变化都是全局的,所以每一个i的值都会变成最终的10
    };
}
a[1](); //返回10
a[6](); //返回10
例子2

这里可以跟以前在里面有一个闭包的例子一起理解

function createFunctions() {
        var result = new Array();
        for (var i = 0; i < 10; i++) {
            result[i] = function () { //这是一个闭包
                //因为闭包保存的是整个createFunctions变量对象,所以当他执行完成的时候(for循环结束),
                //i是等于10的,所以就会是10,由始至终,闭包里面引用的都是一整个变量对象,而不是一个变量
                return i;
            };
        }
        return result; //返回的是一个数组,数组里面每一个项目都是一个function
    }
    var test = createFunctions();
    for (var i = 0; i < 10; i++) {
        //需要执行这个 function 才能够获取里面的值
        console.log(test[i]());//都是10 
    }
//看看区别,这里会传入一个参数来避免使用变量对象的参数
      function createFunctions() {
        var result = new Array();
        for (var i = 0; i < 10; i++) {
            result[i] = function (num) {//这是一个匿名函数,参数是 num
                return function () {// 这是一个闭包,不过这个闭包访问的num是我们传入的num,即使闭包保存一整个变量对象,但是我们将变量对象改成了外面这个匿名函数
                    return num;     //相当于在闭包外面包了一层活动对象,将活动对象改变成能够改变值 num的活动对象
                };
            }(i);//这个匿名函数会立即执行,并且传入了 i 作为 num
        }
        return result; //返回的是一个数组,数组里面每一个项目都是一个function
    }
    var test = createFunctions();
    for (var i = 0; i < 10; i++) {
        //需要执行这个 function 才能够获取里面的值
        console.log(test[i]());//返回0-9
    }

虽然这里是说闭包保存的是整个变量对象,导致了i的值跟着变量对象一起变化,不过也是殊途同归,这里只是替换为做全局对象来做例子

例子3

这里还原到真实的应用






//这里运行报错:Uncaught TypeError: Cannot read property "innerText" of undefined
    at HTMLButtonElement. (
 var buttons = document.querySelectorAll(".button");
 var output = document.querySelector("#output");

 for(var i =0;i

总的来说,那么在以前的js里面要实现块级作用域的话:

要么使用函数作用域,例如在函数里面重新定义变量

要么就使用类似闭包的方式,使用独立的变量

let

let的作用就是将变量保持在块级作用域里面,那就没有了跟其他作用域互抢的情况了.

var会出现变量提升的情况(变量可以在声明前使用),但是let没有

不允许重复声明(var可以,let不可以)

改成用let之后

var a = [];
for (let i = 0; i < 10; i++) {
    a[i] = function () {
        console.log(i);
    };
}
a[1](); // 返回1
a[6](); // 返回6

其他例子也是可以简单的改成let代替var就可以生效了.

块级作用域与函数声明

es5规定函数只能在顶层作用域和函数作用域之中声明,不能再块级作用域声明(一般模式可以使用,但是严格模式不可以使用)

es6规定,明确允许在块级作用域之中声明函数

但是考虑到旧代码的问题,为了减轻因此产生的不兼容问题,ES6在附录B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。

考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

// 函数声明语句
{
  let a = "secret";
  function f() {
    return a;
  }
}

// 函数表达式
{
  let a = "secret";
  let f = function () {
    return a;
  };
}
for循环

for循环还有一个特别之处,就是循环语句部分是一个父作用域,而循环体内部是一个多带带的子作用域。

for (let i = 0; i < 3; i++) { //i在for循环变化
  let i = "abc"; //然后for循环内部的i也设置了一个
  console.log(i);
}
// abc
// abc
// abc

上面代码输出了3次abc,这表明函数内部的变量i和外部的变量i是分离的。

const

const声明一个只读的常量。一旦声明,常量的值就不能改变。

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。

对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。

于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了

const foo = {};

// 为 foo 添加一个属性,可以成功,虽然设置了常量,但是里面的属性还是能够改变
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错,这里看到常量还是设置成功的
foo = {}; // TypeError: "foo" is read-only

如果需要将对象冻结,保证为一个真正的"常量",需要用Object.freeze,而且为了保证排除对象里面包含对象的情况,需要递归冻结

//普通冻结
const foo = Object.freeze({});

// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;

//递归冻结
var constantize = (obj) => {
  Object.freeze(obj);
  Object.keys(obj).forEach( (key, value) => {
    if ( typeof obj[key] === "object" ) {
      constantize( obj[key] );
    }
  });
};
总而言之:

一般情况下,使用const来定义值的存储容器(变量)

只有在值容器明确地被确定将会被改变时才使用let来定义变量

不在使用var

参考引用:

es6-函数的扩展

es实战2015

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

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

相关文章

  • es6学习笔记-函数扩展_v1.0_byKL

    摘要:学习笔记函数扩展函数参数的默认值如果参数默认值是变量,那么参数就不是传值的,而是每次都重新计算默认值表达式的值。属性函数的属性,返回该函数的函数名。箭头函数详细链接参考引用函数扩展 es6学习笔记-函数扩展_v1.0 函数参数的默认值 function Point(x = 0, y = 0) { this.x = x; this.y = y; } var p = ne...

    yuanzhanghu 评论0 收藏0
  • es6学习笔记-箭头函数_v1.0_byKL

    摘要:因为箭头函数本身没有所以不可以当作构造函数,也就是说,不可以使用命令,否则会抛出一个错误。箭头函数不可以使用对象,该对象在函数体内不存在。 es6学习笔记-箭头函数_v1.0 箭头函数使用方法 var f = v => v; //普通函数配合箭头函数写法,这里并且是传参的 //相当于 var f = function(v) { return v; }; /*-----------...

    lushan 评论0 收藏0
  • es6学习笔记-顶层对象_v1.0_byKL

    摘要:学习笔记顶层对象虽然是笔记但是基本是抄了一次大师的文章了顶层对象顶层对象,在浏览器环境指的是对象,在指的是对象。之中,顶层对象的属性与全局变量是等价的。的写法模块的写法上面代码将顶层对象放入变量。参考引用顶层对象实战 es6学习笔记-顶层对象_v1.0 (虽然是笔记,但是基本是抄了一次ruan大师的文章了) 顶层对象 顶层对象,在浏览器环境指的是window对象,在Node指的是gl...

    Meils 评论0 收藏0
  • es6学习笔记-字符串的扩展_v1.0_byKL

    摘要:学习笔记字符串的扩展字符的表示法允许使用的形式表示一个字符,但在之前,单个码点仅支持到,超出该范围的必须用双字节形式表示,否则会解析错误。返回布尔值,表示参数字符串是否在源字符串的头部。,是引入了字符串补全长度的功能。 es6学习笔记-字符串的扩展_v1.0 字符的Unicode表示法 JavaScript 允许使用uxxxx的形式表示一个字符,但在 ES6 之前,单个码点仅支持u00...

    JaysonWang 评论0 收藏0
  • es6学习笔记-module_v1.0_byKL

    摘要:学习模块不是对象,而是通过命令显式指定输出的代码,输入时也采用静态命令的形式。的模块自动采用严格模式命令用于规定模块的对外接口,命令用于输入其他模块提供的功能。该文件内部的所有变量,外部无法获取。 es6 学习-module_v1.0 ES6模块不是对象,而是通过export命令显式指定输出的代码,输入时也采用静态命令的形式。 ES6的模块自动采用严格模式 export命令用于规定模...

    VishKozus 评论0 收藏0

发表评论

0条评论

Youngdze

|高级讲师

TA的文章

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