function show( flag ){
console.log( a );
if( flag ){
var a = 'ghostwu';
return a;
} else {
console.log( a );
return null;
}
}

我们从es5的变量提升开始说起, 由于变量提升的原因, 上述程序, 在第2行和第7行都能访问到a的值, 只不过是undefined, 如果你不熟悉javascript这种变量的预解释机制,可能会认为第2行和第7行会报错, 只有flag为true的时候,变量a才声明了, 其实javascript在词法解释的时候,会把上述代码解释成下面的样子:

        function show( flag ){
var a;
console.log( a );
if( flag ){
a = 'ghostwu';
return a;
} else {
console.log( a );
return null;
}
}

这种机制,在项目中经常误导程序员,哪怕是资深的前端程序员,不小心也容易入坑, 于是ES6引入了块级作用域来强化对变量生命周期的控制.

什么是块级作用域?

1,函数内部

2,块中( 通常指的是一对花括号之间)

es6中使用新的关键词 let 来定义变量, 为块级作用域,上例,如果改成let声明

     function show( flag ){
console.log( a );
if( flag ){
let a = 'ghostwu';
return a;
}else {
console.log( a );
return nul;
}
}

由于let是块级作用域,不会像var一样 产生变量提升, 所以,第2行和第7行 这个时候报错( a is not defined )

只有在flag为true的情况,a会被定义, 而且访问范围在第3行和第6行的大括号之间, 超出这个范围,就访问不到a, 这就是块级作用域

let都有哪些特性呢?

在同一个作用域下,let不能重复定义两个同名的标识符

在不同的作用域下,可以使用同名的标识符

 var a = 'ghostwu';
let a = 'ghostwu2';
 let a = 'ghostwu';
let a = 'ghostwu2';

以上两种方式,都会报重定义错误(Identifier 'a' has already been declared)

         let a = 10;
if( a ){
let a = 100;
console.log( a ); //
}
console.log( a ); //10

以上这种方式,不会报错,因为是两个不同的作用域

let的经典应用

在4个按钮中,获取当前被点击按钮的索引

      <script>
window.onload = function(){
var aInput = document.querySelectorAll("input");
for( var i = 0; i < aInput.length; i++ ){
aInput[i].onclick = function(){
alert( i );
}
}
}
</script> <input type="button" value="按钮1">
<input type="button" value="按钮2">
<input type="button" value="按钮3">
<input type="button" value="按钮4">

如果,我们用上面的方法做, 每个按钮点击之后 i 都是4, 因为4个按钮绑定完事件之后,i的值就变成了4, 下次点击按钮的时候,所有的都是4, 因为 i = 4 是共享的

通常,我们会在每个按钮上,加一个自定义索引 绑定 对应的 i 值,再借助this关键字,就可以如愿以偿,如下:

         window.onload = function(){
var aInput = document.querySelectorAll("input");
for( var i = 0; i < aInput.length; i++ ){
aInput[i].index = i;
aInput[i].onclick = function(){
alert(this.index);
}
}
}

还有另一种方法,就是借用立即表达式+闭包的形式, 如下:

         window.onload = function(){
var aInput = document.querySelectorAll("input");
for( var i = 0; i < aInput.length; i++ ){
aInput[i].onclick = (function( j ){
return function(){
alert( j );
}
})( i );
}
}

而采用let关键字, 利用块级作用域的特性,就可以轻松达到目的

         window.onload = function(){
var aInput = document.querySelectorAll("input");
for( let i = 0; i < aInput.length; i++ ){
aInput[i].onclick = function(){
alert( i );
};
}
}

var在全局作用域下,会把属性绑定到window上,从而可能产生覆盖属性的隐患,而let关键字只是会遮蔽它,并不会覆盖window上的同名属性

         var a = 10;
console.log( a ); //
console.log( window.a ); //
console.log( 'a' in window ); //true let user = 'ghostwu';
console.log( user ); //ghostwu
console.log( window.user ); //undefined
console.log( 'b' in window ); //false /*
var RegExp = 'ghostwu';
console.log( RegExp ); //ghostwu
console.log( window.RegExp ); //ghostwu
console.log( 'RegExp' in window ); //true
*/ let RegExp = 'ghostwu';
console.log( RegExp ); //ghostwu
console.log( window.RegExp ); //function RegExp() { [native code] }
console.log( 'RegExp' in window ); //true

const关键字是用来定义常量的,它有如下特性:

.块级作用域

.声明的时候,必须赋予初始值

.不能被重新赋值

.如果值是一个对象, 那么对象里面的属性是允许被修改的

.不能跟其他标识符重名

         const user = 'ghostwu';
console.log( user );
user = 'zhangsan'; //报错, 不能重新赋值
 const user; //报错,定义的时候 没有给初始值
         const user = {
name : 'ghostwu'
};
console.log( user.name ); //ghostwu
user.name = 'zhangsan'; //对象的属性允许被修改
console.log( user.name ); //zhangsan
        const user = {
name : 'ghostwu'
};
user = { //报错,不能重新给user赋值
name : 'zhangsan'
}
console.log( user.name ); //报错
         var a = 10;
const a = 10; // 报错,重定义错误
         let a = 10;
const a = 10; //报错,重定义错误
        if ( true ) {
const a = 10;
console.log( a ); //
}
console.log( a ); //报错:a is not defined

最新文章

  1. java21
  2. js正则中的贪婪和非贪婪模式问题总结
  3. (Python) 安装、基本语法
  4. 解决Electron加载带jquery的项目报错问题
  5. 利用caffe生成 lmdb 格式的文件,并对网络进行FineTuning
  6. 人民币符号¥在css和html正确显示
  7. SignTool.exe(签名工具)
  8. UIView 和 UIWindow 的学习内容
  9. 《Effective C++ 》学习笔记——条款03
  10. 企业部署Windows 8 Store 风格应用
  11. 初涉IPC,了解AIDL的工作原理及使用方法
  12. Ionic2生成的main.js执行时间10s+
  13. JavaWeb中过滤器Filter的使用示例
  14. Love2D游戏引擎制作贪吃蛇游戏
  15. Harbor镜像迁移
  16. pyglet player sound
  17. 【shell编程】之基础知识-流程控制
  18. js 原生图片上传
  19. lodash用法系列(5),链式
  20. python3和2的区别

热门文章

  1. 对js运算符“||”和“&amp;&amp;”的总结
  2. An impassioned circulation of affection
  3. vue中数据双向绑定注意点
  4. docker 初识之二(简单发布ASP.NET Core 网站)
  5. 【LeetCode】2. Two Sum
  6. 【Android Developers Training】 101. 显示快速联系人挂件(Quick Contact Badge)
  7. [Android FrameWork 6.0源码学习] ViewGroup的addView函数分析
  8. 也谈TDD,以及三层架构、设计模式、ORM……:没有免费的午餐
  9. ReactNative开发工具有这一篇足矣
  10. H3CNE实验:配置基于端口划分的VLAN及Trunk