let命令
用于声明变量,声明的变量只在let命令所在的代码块有效
for循环的计数器就很适合用let命令
for循环使用let------特别之处
一 循环变量那个部分相当于父作用域
二 循环内部相当于一个子作用域
let命令不存在变量提升
console.log(a);//报错
let a = 'abc';
暂时性死区-------使用let命令声明变量之前,该变量都是不可用的
如果某个块级作用域下存在let,它声明的这个变量会绑定在这个作用域,不受外界影响
var temp = 'abc';
if(true){
console.log(temp); //会报错
let temp = 'b';
}
拓展:es6明确规定,区块中存在let和const命令,则这个区块对这些命令 声明的变量从一开始就形成了封闭作用域。只要在声明前使用了这些变量都会报错。
let不允许重复声明—let不允许在同个作用域下重复声明同一个变量
{
var a = 1;
let a = 2;//报错
}
{
let a = 1;
let a = 2;//报错
}
function fn(a) {
let a = 2;//报错 因为形参存在变量提升
}
块级作用域
es5没有块级作用域
es6的块级作用域
es6允许块级作用域内部任意嵌套,外层无法访问内层用let声明的变量
es6出现 导致了立即执行函数不再必要了
函数声明
es5的函数声明只能在全局作用域或者函数作用域下声明,其他都是不合法的
es6可以,注意:es6在块级作用域声明函数,应该使用函数表达式而不是函数声明
es6的块级作用域允许声明函数的规则只在使用大括号的情况下成立,没有大括号就会报错
do表达式
块级作用域是一个语句,将多个操作封装在一起,没有返回值;
do表达式时块级作用域变为表达式,即可以返回值
let x = do {
let t = fn();
t = t+2;
};//x会得到整个块级作用域的返回值
const命令
const声明一个只读的常量,一旦声明了,常量值就不能改变(一旦声明就必须立即初始化,不能留到以后赋值)。其实是保证变量指向的那个内存地址不能改变
不能重复声明
只能带当前作用域使用
存在暂时性死区
const b;//报错
const a = 1;
a = 2;//报错
es6声明变量的6种方法
var
functtion
let
const
import
class
顶层对象属性
顶层对象在浏览器环境下就是window对象,在node环境时global对象。
在es5种,顶层对象的属性和全局变量是等价的
var a = 1; //= window.a = 1;
a = 2; //window.a 输出的结果也是2
es6中新增的4种声明变量方式不属于window对象
const a = 2;
console.log(window.a) //underfined
在node模块和es6模块中,this返回的是当前模块
变量解构赋值
解构:es6允许按照一定模式从数组和对象提取值,然后对变量进行赋值
基本用法
let a = 1;
let b = 2;
let [c,d] = [1,2];//属于模式匹配,只要等号两边模式相同,
//左边的变量就会被赋予对应的值
let [foo, [[bar], baz]] = [1, [[2], 3]];
默认值
解构赋值允许指定默认值
let [flag = true] = [];
let [flag1 = true] = [underfined]; //true
let [flag2 = true] = [null]; //null
let [x = 1, y = x] = [] //1 1
let [x = 1, y = x] = [2] //2 2
let [x = 1, y = x] = [1,2] //1 2
let [x = y, y = 1] = [] //报错
对象解构赋值
对象的解构与数组有一个重要的不同。
数组的元素是按次序排列的,变量的取值由它的位置决定
对象的属性没有次序,变量必须和属性同名才能取到正确的值
let {a,b} = {a : 1, b : 2}//1 2
let {c , b} = {a : 1, b : 2}//c undefined
如果不一致 必须写成
let {a : c , b} = {a : 1, b : 2}// c = 1 b = 2 a只是匹配模式
let {e : c , b} = {a : 1, b : 2} //报错 ,因为等号右边没有e的属性
var {x ;y = 3} = {} //y = 3
var {x : y = 3} = { y = 5} // y = 5
属性值如果是underfined 使用默认值 ,如果是null 则使用null
如果使用变量声明后再进行解构赋值,则
let x;
{x} = {x = 1} //报错
需要写成
({x} = {x = 1})
数组是一个特殊的对象
let arr = [1,2,3,4];
let {0 : first, [arr.length - 1] : last} = arr;
first = 1; last = 4;
字符串解构赋值
const [a,b,c,d,e] = 'hello';a=h b=e c=l d=l e=o
const {length : len} = 'hello';
len = 5
数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值时,则会先转为对象
函数形参的解构赋值
function add([a,b]){
return a + b
}
add([1,2]) //3
function move ({x = 0, y = 0} = {}){
return [x,y];
}
move({x : 8 , y : 3}) [8,3]
move({x : 8}) [8,0]
move({}) [0,0]
move()[ 0,0]
function move ({x, y} = {x = 0, y = 0}){
return [x,y];
}
move({x : 8 , y = 3}) [8,3]
move({x : 8}) [8,undefinerd]
move({}) [undefinerd,undefinerd]
move()[0,0]
underfined就会触发函数的默认值
[1,undefined,true].map((x=3) => x);
解构赋值不能使用圆括号的情况
一、变量声明语句
上面的对象和数组解构式子都是变量声明语句,这些都不能使用
二、函数参数
三、赋值语句的解构模式
({x}) = {x = 1} {x} 这个就是模式 //报错
解构赋值能使用圆括号的情况
只有一种:赋值语句的非解构模式
[(x)] = [1]
({p : (x)} = {p = 1}) 对象先声明再结构赋值只能使用这种
结构赋值的用途
一、改变变量的值
let a = 1;
let b = 2;
[a, b] = [b. a];
二、从函数或返回多个值或者返回一个对象
function fn (){
return [1,2,3];
}
let [a,,b,c] = fn();
function fn2 (){
return {name ; '张三', age : 16};
}
let {namem, age} = fn();
三、函数参数的定义-----方便实参形参一一对应
有序的 function f([a,b,c]){} f([1,2,3])
无序的 function f({x,y,z}){} f({z : 1, x = 2, y = 3})
四、提取JSON数据
五、函数参数默认值
六、遍历Map结构
七、输入模块的指定方法
函数的扩展
函数默认值
函数的length属性
(function (a,b) {}).length //2
(function (a,b=1) {}).length //1
(function (a=1,b=2) {}).length //0
(function (a=1,b) {}).length //0
作用域
当函数的形参设置了默认值,函数进行声明时,会形成一个单独作用域,等到初始化结束,这个作用域才会消失
var x = 4;
function fn (y=x) { //函数调用时 (y=x)已是一个单独的作用域
//函数调用没传值,且在这个作用域找不到x,
//所以去window找。跟函数内部无关
let x = 3
console.log(y);
}
fn();
var x= 1;
function fn (x,y = function () {{ x = 2 }) {
var x = 4;
y();
console.log(x) //4
}
fn();
===========================
var x= 1;
function fn (x,y = function () {{ x = 2 }) {
x = 4;
y();
console.log(x) //2
}
fn();