定义(声明)变量
-
let命令
-
基本用法
let用来声明变量,用法类似于var,但是let声明的变量,只有在let命令所在的代码块内有效。{ let a=10; var b=10; } console.log(a);//ReferenceError: a is not defined. console.log(b);//10
for循环的计数器 使用let不会有变量提升引起的泄露
for(let 1=0;i<10;i++){ //... } console.log(i);//ReferenceError:i is not defined //变量i只在for循环体内有效,在循环体外引用就会报错。
注意:在for循环中,设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
for(let i =0;i<3;i++){ let i='abc'; console.log(i); } //结果 3此abc abc abc abc 说明循环内部的变量i与循环变量i不在同一个作用域。
-
不存在变量提升
var命令存在变量提升的现象,即变量可以在声明之前使用,值为undefined。
let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。//var 的情况 console.log(foo);//输出undefined var foo=2; ----变量提升后---- var foo; console.log(foo); foo=2; //let的情况 console.log(bar);//输出ReferenceError let bar=2;
上面代码中,变量foo用var命令声明,会发生变量提升,即脚本开始运行时,变量foo已经存在了,但是没有值,所以会输出undefined。
变量bar用let命令声明,不存在变量提升。这表示在声明他之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误。 -
暂时性死区
只要在块级作用域内用let声明和外层同名的变量,它所声明的变量就绑定(binding)这个区域,不再受外部的影响。var tmp =123; if(true){ tmp='abc'; let tmp; console.log(tmp);//Uncaught ReferenceError: tmp is not defined } /* 上面代码中,tmp首先为全局变量,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量之前,对tmp赋值会报错。 */
ES6规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错,这在语法上称为“暂时性死区”(temporal dead zone,简称TDZ)
例:tmp='abc';//ReferenceError console.log(tmp);//ReferenceError let tmp;//TD结束 console.log(tmp);//undefined tmp=123; console.log(tmp);//123 //总之在let命令声明变量之前,都属于变量的暂时性死区
-
不允许重复声明变量
let不允许在相同作用域内,重复声明同一个人变量。{ let a=10; var a=1;//报错 } { let b=10; let b=1;//报错 }
也不能在函数内部重新声明参数
function f(a){ let a;//报错 if(true){ let a;//不会报错 } }
-
-
const命令
- const与let的用法基本一致,let有的特性const也有;区别在于const声明一个只读的常量,一旦声明,常量的值就不能改变。
如:
const PI =3.1415; PI =3; // Uncaught TypeError: Assignment to constant variable.
补充:const声明的变量不能改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
const foo; //Uncaught SyntaxError: Missing initializer in const declaration
- const本质
const实质上保证的,并不是变量的值不改动,而是变量指向的那个内存地址所保存的数据不得改动。
对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。
但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针式固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。
例:const foo ={}; foo.prop=123;//为foo添加一个属性可以成功 console.log(foo);//{prop: 123} foo ={};//将foo指向另一个对象,报错 //Uncaught TypeError: Assignment to constant variable. const a=[]; a.push('Hello');//可执行 a.length=0;//可执行 a=['Dave'];//Uncaught TypeError: Assignment to constant variable.
- const与let的用法基本一致,let有的特性const也有;区别在于const声明一个只读的常量,一旦声明,常量的值就不能改变。
-
顶层对象的属性
顶层对象,在浏览器环境指的式window对象,在Node指的是global对象(全局对象)。
- 在ES5中,顶层对象的属性与全局变量是等价的。
如:
window.a = 1; console.log(a);//1 a = 2; console.log(window.a);//2
- ES6规定:
- var和function声明的全局变量,依旧是顶层对象的属性
- let和const、class声明的全局变量不属于顶层对象的属性
如:
var a= 1; console.log(window.a);//1 let b=1; console.log(window.b);//undefined
- 在ES5中,顶层对象的属性与全局变量是等价的。
-
global对象
- JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。
全局对象不是任何对象的属性,所以它没有名称。 - global对象在不同的环境中实现也是不一样的
如:- 在浏览器里,就是window
- 在Node里,就是global
- 关于this变量
- 全局环境中,this会返回顶层对象。但是,Node模块和ES6模块中,this返回的是当前模块。
- 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是严格模式下,这时this会返回undefined。