1,let,const:
let:
if(true){
let a=12;
}
console.log(a);//error
有上述栗子可以看出来,大括号内是一个独立的作用域,由此es6中提出了块级作用域;
什么是块级作用域:
{
//块级作用域
}
if(){}
for(){}
while(){}
let与var区别:
1>
var a=12;
function fn(){
var a=5;
console.log(a);//5
}
fn();
var a=12;
function fn2(){
console.log(a);//undefined
var a=5;
}
fn2();
用var在函数中的操作之后声明变量,相当于对函数内定义的变量提升了,就是进行了预解析。
let a=12;
function fn(){
let a=5;
console.log(a);//5
}
fn();
var let=12;
function fn2(){
console.log(a);//error TDZ 开始 暂时性死区
var let=5;//TDZ 结束
}
fn2();
而用let定义的变量,没有预解析,不存在变量提升。
在代码块内,只要是let定义的变量。在定义之前使用都会报错,必须先定义在使用。
2>
var a=12;
var a=5;
console.log(a);//5
用var定义的变量可以重复定义,程序会正常运行,后面定义的会覆盖前面的。
let a=12;
let a=5;
console.log(a);//error
用let定义的变量不能重复定义,
3> 在同级作用域不能重复定义。
for(var i=0;i<3;i++){
//todo
}
console.log(i);//3
在for循环中用var定义的变量,在循环外也可以用,
for(let i=0;i<3;i++){
//todo
}
console.log(i);//error
用let只能在for内使用
for(let i=0;i<3;i++){
let i='abc';
console.log(i);//abc abc abc
}
在for循环中,有两个作用域,小括号是父级作用域,而花括号是子级作用域
在同级作用域不能重复定义。
下面给大家说一个我们经常会遇到的问题:
for (var i=1; i<=9; i++) {
setTimeout( function timer(){
console.log( i );
},1000 );
}
上面的代码,由于setTimeout是异步的,那么在真正的1000ms结束前,其实10次循环都已经结束了,最终只会输出10。
我们有两种解决方法:
第一种就是let方法:
for (let i=1; i<=9; i++) {
setTimeout( function timer(){
console.log( i );
}, 1000 );
}
还有另外一种方法,改成
for (var i=1; i<=9; i++) {
(function(j){
setTimeout( function timer(){
console.log( j );
}, 1000 );
})( i );
}
这两种方法都是通过解决变量作用域的问题来实现的
let声明的变量仅在块级作用域有效,所以这里的i只在本轮循环有效果,每次循环的i其实都是一个新的变量 中。
const:
定义常量,在定义是必须有值,那就是不可修改的。
但是特殊的,当它定义的是对象类型时,对象内的属性值可以改变。因为对象是引用类型,返回的时对象的地址,而const定义的常量名称接受的也是对象的地址,对象内部属性可以改变,地址不能变。(freeze)
2.解析赋值:
(数组、对象、字符串、布尔值、函数参数、数值)
数组:
例:
let a,b;
[a,b]=[1,2];
console.log(a,b);//1,2
let a,b;
[a,...b]=[1,2,3,4,5,6];
console.log(a,b);//1,数组[2,3,4,5,6]
let a,b;
[a,,...b]=[1,2,3,4,5,6];
console.log(a,b);//1,数组[3,4,5,6]
其中,,之间占位;
let a,b;
[a,b=3]=[1];
console.log(a,b);//1,3
给变量设置默认值,使没有在结构上形成配对的变量也有值,不然最后变量输出为undefined。
对象
let o={
p:42,
q:true
}
let {p,q}=o;
console.log(p,q);//42,true
特别重要的,应用于前后端通信,json格式:
let metaData={
title:'abc',
test:[
title:'test',
desc:'description'
]
}
let{title:esTitle,test:[{title:cnTitle}]}=metaData;
console.log(esTitle,cnTitle);
3.正则:
在 ES5 中,RegExp构造函数的参数有两种情况。
第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。
var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;
第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷贝。
var regex = new RegExp(/xyz/i);
// 等价于
var regex = /xyz/i;
RegExp构造函数的参数是一个正则表达式的时候,ES5 不允许此时使用第二个参数添加修饰符,否则会报错。
var regex = new RegExp(/xyz/, 'i');
// Uncaught TypeError: Cannot supply flags when constructing one RegExp from another
在es6中有两个参数,允许第一个参数是正则表达式,同时允许第二个参数再去填写修饰符,而第二个参数的修饰符会覆盖第一个正则表达式所用的修饰符。
new RegExp(/abc/ig, 'i').flags
// "i"
flags:es6新增的用来获取正则对象修饰符的属性。
y修饰符:
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]
r1.exec(s) // ["aa"]
r2.exec(s) // null
y修饰符与es5中的g修饰符都是全局匹配,但是也有不同之处,g修饰符是从上次匹配的位置继续寻找,直到找到匹配的位置,而y修饰符则需要第一个字符就要匹配成功。
u修饰符:
在处理的字符串中有大于2个字节的字符加u,es5中的.修饰符的定义为可匹配所有字符,在es6中修改了这其中的bug,.修饰符不能匹配大于2字符长度的字符。
s修饰符:dotAll 模式
正则表达式中,点(.)是一个特殊字符,代表任意的单个字符,但是行终止符除外。
以下四个字符属于”行终止符“。
U+000A 换行符(\n)
U+000D 回车符(\r)
U+2028 行分隔符(line separator)
U+2029 段分隔符(paragraph separator)
/foo.bar/.test('foo\nbar')
// false
但是,很多时候我们希望匹配的是任意单个字符,这时有一种变通的写法。
/foo[^]bar/.test('foo\nbar')
// true
这种解决方案毕竟不太符合直觉,所以现在有一个提案,引入/s修饰符,使得.可以匹配任意单个字符。
/foo.bar/s.test('foo\nbar') // true
这被称为dotAll模式,即点(dot)代表一切字符。所以,正则表达式还引入了一个dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式。
const re = /foo.bar/s;
// 另一种写法
// const re = new RegExp('foo.bar', 's');
re.test('foo\nbar') // true
re.dotAll // true
re.flags // 's'
/s修饰符和多行修饰符/m不冲突,两者一起使用的情况下,.匹配所有字符,而^和$匹配每一行的行首和行尾。