[js高手之路] es6系列教程 - var, let, const详解

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不能重复定义两个同名的标识符

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

1 var a = ‘ghostwu‘;
2 let a = ‘ghostwu2‘;
1 let a = ‘ghostwu‘;
2 let a = ‘ghostwu2‘;

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

let a = 10;
        if( a ){
            let a = 100;
            console.log( a ); //100
        }
        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 );  //10
        console.log( window.a ); //10
        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关键字是用来定义常量的,它有如下特性:

.块级作用域

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

.不能被重新赋值

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

.不能跟其他标识符重名

1      const user = ‘ghostwu‘;
2        console.log( user );
3        user = ‘zhangsan‘; //报错, 不能重新赋值

1 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;2

const a = 10; // 报错,重定义错误

1         let a = 10;

2         const a = 10; //报错,重定义错误

1        if ( true ) {

2             const a = 10;

3             console.log( a ); //10

4         }

5         console.log( a ); //报错:a is not defined

时间: 2024-10-13 21:47:20

[js高手之路] es6系列教程 - var, let, const详解的相关文章

[js高手之路] es6系列教程 - 迭代器与生成器详解

什么是迭代器? 迭代器是一种特殊对象,这种对象具有以下特点: 1,所有对象都有一个next方法 2,每次调用next方法,都会返回一个对象,该对象包含两个属性,一个是value, 表示下一个将要返回的值.另一个是done,他是一个布尔值,用来表示该迭代器是否还有数据可以返回. 3,迭代器还会保存一个内部指针指向当前集合中的值 设计模式中有个迭代模式,跟迭代器是差不多的,我之前有写过2篇文章关于迭代模式: [js高手之路] 设计模式系列课程 - 迭代器(1) [js高手之路] 设计模式系列课程 -

[js高手之路] es6系列教程 - promise常见用法详解(resolve,reject,catch,then,all,race)

关于promise我在之前的文章已经应用过好几次,如[js高手之路]Node.js+jade+express+mongodb+mongoose+promise实现todolist,本文就来讲解下promise的常见用法. 为什么会有promise,他的作用是什么? promise主要是为了解决js中多个异步回调难以维护和控制的问题. 什么是promise? 从图中,我们可以看出,Promise是一个函数,这个函数上有在项目中常用的静态方法:all, race, reject,resolve等,原

[js高手之路] es6系列教程 - 迭代器,生成器,for...of,entries,values,keys等详解

接着上文[js高手之路] es6系列教程 - 迭代器与生成器详解继续. 在es6中引入了一个新的循环结构for ....of, 主要是用来循环可迭代的对象,那么什么是可迭代的对象呢? 可迭代的对象一般都有Symbol.iterator属性,你可以在控制台中用console.dir打印数组,Map,Set,在他们的原型对象(prototype)上面就能找到.这个属性与迭代器密切相关,通过该函数可以返回一个迭代器,下文,我会举一个例子.一般来说所有的集合对象(数组,Set,Map 以及字符串)都是可

[js高手之路] es6系列教程 - new.target属性与es5改造es6的类语法

es5的构造函数前面如果不用new调用,this指向window,对象的属性就得不到值了,所以以前我们都要在构造函数中通过判断this是否使用了new关键字来确保普通的函数调用方式都能让对象复制到属性 1 function Person( uName ){ 2 if ( this instanceof Person ) { 3 this.userName = uName; 4 }else { 5 return new Person( uName ); 6 } 7 } 8 Person.proto

[js高手之路] es6系列教程 - Map详解以及常用api

ECMAScript 6中的Map类型是一种存储着许多键值对的有序列表.键值对支持所有的数据类型. 键 0 和 ‘0’会被当做两个不同的键,不会发生强制类型转换. 如何使用Map? let map = new Map(); 常用方法: set( 键,值 ):  添加新的键值对元素 get( 键 ): 获取键对应的值,如果这个值不存在,返回undefined 1 let map = new Map(); 2 map.set( '0', 'ghostwu' ); 3 map.set( 0, 'gho

[js高手之路]设计模式系列课程-发布者,订阅者重构购物车

发布者订阅者模式,是一种很常见的模式,比如: 一.买卖房子 生活中的买房,卖房,中介就构成了一个发布订阅者模式,买房的人,一般需要的是房源,价格,使用面积等信息,他充当了订阅者的角色 中介拿到卖主的房源信息,根据手头上掌握的客户联系信息(买房的人的手机号),通知买房的人,他充当了发布者的角色 卖主想卖掉自己的房子,就需要告诉中介,把信息交给中介发布 二,网站订阅信息的用户 订阅者角色:需要订阅某类信息的网民,如某个网站的javascript类型文章 发布者角色:邮箱服务器,根据网站收集到的用户订

[js高手之路]深入浅出webpack教程系列9-打包图片(file-loader)用法

[js高手之路]深入浅出webpack教程系列索引目录: [js高手之路]深入浅出webpack教程系列1-安装与基本打包用法和命令参数 [js高手之路]深入浅出webpack教程系列2-配置文件webpack.config.js详解(上) [js高手之路]深入浅出webpack教程系列3-配置文件webpack.config.js详解(下) [js高手之路]深入浅出webpack教程系列4-插件使用之html-webpack-plugin配置(上) [js高手之路]深入浅出webpack教程系

[js高手之路]设计模式系列课程-组合模式+寄生组合继承实战新闻列表

所谓组合模式,就是把一堆结构分解出来,组成在一起,现实中很多这样的例子,如: 1.肯德基套餐就是一种组合模式, 比如鸡腿堡套餐,一般是是由一个鸡腿堡,一包薯条,一杯可乐等组成的 2.组装的台式机同理,由主板,电源,内存条,显卡, 机箱,显示器,外设等组成的 把一个成型的产品组成部件,分成一个个独立的部件,这种方式可以做出很多灵活的产品,这就是组合模式的优势 比如:家用台式机电脑,要求配置比较低, 这个时候只需要主板+电源+内存条+机箱+显示器+外设就可以了,不需要配置独立显卡 鸡腿堡+鸡翅+紫薯

史上最详细的Android Studio系列教程五--Gradle命令详解与导入第三方包

Android Studio + Gradle的组合用起来非常方便,很多第三方开源项目也早都迁移到了Studio,为此今天就来介绍下查看.编译并导入第三方开源项目的方法. Sublime + Terminal编译并查看源码 首先来给大家介绍一种简便并且个人最喜欢的一种办法.很多时候我们在GitHub上看到一个不错的开源项目,一般有两种需求,阅读源码和查看运行效果,如果是单纯的查看源码我更喜欢用一些轻量级编辑器,如vim,sublime等,vim不是很熟练,所以个人一种都习惯用sublime来查看