1. let和const命令

let命令

let是新增加的语法,该方法的用法和var是一样的,区别在于let声明的变量只能let所在的代码块内有效

{
    let name='Tom';
    var age=10;
}
console.log(name); //
console.log(age); //10

利用这一特性我们可以用来实现优化for循坏

var a=[];
for(let i=0;i<10;i++){
    a[i]=function(){
        return i;
    };
}
console.log(a[6]()); //6
//在之前如果我们使用var定义变量,那么a[6]()的结果会是10,因为var定义的是全局变量,在循环中定义的i是全局变量,每一个a[i]返回的i的值都会指向全局的i,而全局的i在循环结束后值为10,所以导致运行的时候最后的值都是循环后的最后一轮的值,而使用了let后,每一次循环的i都是新的变量,在javascript的引擎内部会记住上一轮循环的值,在初始化本轮的变量i时,就会在上一轮的基础上进行计算并对本次的计算记过进行赋值,使用let对i赋值相当于我们在es5中使用闭包存储每一次i变量值的操作

//es5
var a=[];
var loop=function (i) {
    a[i]=function () {
        return i
        }
    }
for(var i=0;i<10;i++){
    loop(i)
}
console.log(a[6]()); //6

//另外在for循环中使用let时需要注意,在循环处设置的变量那部分是属于父作用域,而循环体内部则是属于单独子作用域

for(let i=0;i<3;i++){

    let i='abc';

    console.log(i);
}
//在循环结束后会打印三次'abc',这说明循环内部的变量i和for循环定义的变量i不在同一个作用域,有各自单独的作用域,而如果我们使用var进行定义则会报错

let定义的变量不会发生变量提升的情况,也就是我们之前说的变量的预解析,let定义的语法一定要在let之后对变量进行引用,否则会报错,我们可以比较一下使用var和let定义变量的区别

console.log(name); //undefined
var name='tom';

console.log(age); //index.html:15 Uncaught ReferenceError: age is not defined
let age=18;

let定义变量会有一个暂时性死区的现象,简称TDZ,在ES6中明确规定,如果在块级作用域中存在let或const命令,从一开始就形成了封闭的作用域,凡是在let声明变量之前使用该变量是不合法的,会报错

var num=2;

if(true){
    num='hello';

    let num;//index.html:15 Uncaught ReferenceError: num is not defined
}

//也就是说在块级作用域中,在let定义的变量之前使用该变量都是报错,即使该变量已经在全局作用域中定义

还有一些其它情况的死区的现象,如下

function bar(x=y,y=2){
    return [x,y];
}
bar();//index.html:12 Uncaught ReferenceError: y is not defined

function bar(x=2,y=x){
    return [x,y]
}
console.log(bar());//[2,2]

//在第一个函数中,因为在参数x=y时,y还没有声明,属于死区
//在第二个函数中,参数y=x时,x已经赋值为2

var x=x; //undefined

let x=x; //Uncaught ReferenceError: y is not defined

//使用var声明变量时,var x=x; 可以理解为var x; x=undefined;
//而使用let时,由于不存在变量提升,所以改写法相当于在没有声明x时去使用x,所以会报错

let不允许在相同作用域内,重复声明同一个变量

{
    var i=1;
    let i=2
}  //Uncaught SyntaxError: Identifier 'i' has already been declared

{
    let i=1;
    let i=2;
} // Uncaught SyntaxError: Identifier 'i' has already been declared

function fn(arg){
    let arg;
} //Uncaught SyntaxError: Identifier 'arg' has already been declared

function fn(arg){
    {
        let arg;
    }
}//不报错

//这里我们可以看出,1.函数的参数和函数内部时属于一个作用域内 2.使用了let定义变量后,不允许再次重复声明,即使是var也不可以

ES6允许任意的块级作用域嵌套,外层的块级作用域无法获取内层的块级作用域内的变量,内层作用域可获取外层作用域定义的变量,内层可以定义与外层相同的变量

 {
    let name='xm';
    let age=18;
        {
            let name='Tom'
            console.log(age);
        }
    }

let命令可以形成块级作用域,只在声明变量的块级作用域内起作用,不可以对变量进行重复声明,不会进行变量名提升,存在暂死性区域,在let定义变量之前对该变量进行引用会报错,在块级作用域外不能获取let定义的变量

const命令

const声明一个只读的常量,一旦声明,常量的值就不能更改,同时也意味着一旦我们使用const声明常量,需要立刻赋值,不能保留到以后赋值

const x='Tom';
    
x='xm';//index.html:14 Uncaught TypeError: Assignment to constant variable.

const x;

console.log(x);//Uncaught SyntaxError: Missing initializer in const declaration

const同样不支持变量提升,只在声明所在的块级作用域内有效,也存在暂死性区域,只能在声明的位置后面使用,并且不可以重复声明

const本质

const实际上保证的并不是变量的值不得改动,而是变量指向的内存地址不能改动,那么我们都知道,对于简单类型的数据来说,值就保存在变量指向的内存地址中,因此地址等同于值,但对于复杂类型的数据来说,地址保存的只是一个指针,const只能保证这个指针是固定的,并不能保证指针指向的地址内的数据结构不变

const obj={};

obj.name='xm';  
console.log(obj.name);//xm

obj={};//Uncaught TypeError: Assignment to constant variable.

//我们为const定义的对象添加数据并不会报错,而且可以获取到添加的数据,但是如果想要为obj重新赋值会立即报错

const a=[];

a.push('hello');
a.length=0;

a=['hi'];//Uncaught TypeError: Assignment to constant variable.

//对于const定义的复杂类型,我们可以对其属性和数据进行添加或修改,但不能改变其地址

const用于声明一个不可变的变量,如果是简单类型的数据,那么该值不可以被修改,如果是复杂数据类型的话,可以对其属性进行修改,对数据进行添加,但是不能对其进行重新赋值操作,coust声明的变量不能被提升,只能在声明的块级作用域中使用,同样具有暂死性区域,不可以进行重复定义

在之前,我们使用var定义一个全局变量,那么该变量会被挂载到window(顶层对象)上,这也造成来了只要是全局属性,那么一定是顶级对象的属性,为了规避这个问题同时保持兼容性,在ES6中规定var和function定义的全局变量依旧是顶层对象的属性,但是由let,coust,class声明的全局变量,不属于顶层对象的属性,也就是说从ES6开始,顶层属性将会逐渐与全局变量脱钩

var a="a";
let b="b";
console.log(window.a); //a
console.log(window.b); //undefined
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容

  • let 命令 块级作用域 const 命令 顶层对象的属性 global 对象 let 命令 基本用法 ES6 新...
    嘉奇呦_nice阅读 1,620评论 0 2
  • let 和 const 命令 let 命令 块级作用域 const 命令 顶层对象的属性 gl...
    安小明阅读 977评论 0 0
  • let 命令 块级作用域 const 命令 顶层对象的属性 global 对象 let 命令 基本用法 ES6 新...
    卞卞村长L阅读 584评论 0 0
  • 1.let命令 基本用法 ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在le...
    angelwgh阅读 282评论 0 0
  • 昨日雨还寒,漫道西风卷。四顾寻梅不可得,静待花期展。 一夜早春来,和煦清风暖。尽褪貂裘戏纸鸢,不惧归途晚。
    磨坊的驴子阅读 316评论 0 5