var a = [];
for(var i=0;i<10;i++){
a[i] = function(){
console.log(i)
}
}
a[6]();//10
上面是var声明的,全局有效,每次循环都会覆盖上一次,最后输出的就是最后一轮的i值
var a = [];
for(let i=0;i<10;i++){
a[i] = function(){
console.log(i)
}
}
a[6]();//6
let声明的i,只在本轮循环中有效,每次声明的其实都是一个新的变量,最后输出6
console.log(foo);//ReferenceError
let foo = 3;
var tmp = 123;
if(true){
tmp = 'abc';//ReferenceError
let tmp;
}
总之,在代码块内,使用let声明变量之前,该变量都是不可使用的,在语法上成为“暂时性死区”;
4. 不允许重复声明
{
let a = 'test';
function f(){
return a;
}
f();//test
}
f();//test
建议:
{
let a = 'test';
let f = function(){
return a;
}
f();//test
}
var message = "test";
let age = 12;
//报错
const message = "test1";
const age = 15;
const foo = {};
foo.prop = 123;
foo.prop;//123
//const声明的常量只能在当前代码块内有效,如果想设置跨模块的常量:
//test.js模块中
export const A = 1;
export const B = 2;
调用:
1、
import Test from "./test";
console.log(Test.A);//1
2、
import {A,B} form "./test";
console.log(A);//1
ES6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称为 解构
ES5:
var a = 1;
var b = 2;
ES6:
var [a,b] = [1,2]
以上模式匹配写法
数组嵌套解构
let [a,[[b],c]] = [1,[[2],3]];
a//1
b//2
c//3
let [head,...tail] = [1,2,3,4];
head//1
tail//[2,3,4]
如果解构不成功,变量的值就是undefined
let [a] = [];
let [b,a] = [1];
//以上两种对于a都是解构不成功
不完全解构
等号左边的模式只匹配等号右边数组的一部分,这种情况解构依然成功
let [a,[b],c] = [1,[2,3],4,5];
a//1
b//2
c//4
等号右面不是数组,直接报错
//一下都报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
对于Set解构,也可以使用数组的解构赋值
let [x,y,z] = new Set(["a","b","c"]);
x //a
解构允许默认值
let [foo = true] = [];
foo //true
let [x,y='b'] = [a];
let [x,y='b'] = [a,undefined];
//以上两种输出都是
x //a
y //b
let [x = 1] = [undefined];
x //1
let [x = 1] = [null];
x //null
由于null不严格等于undefined,默认值不生效
如果默认值是表达式,那么这个表达式是惰性求值的,即只有在用到时才会求值
function f(){
console.log('haha')
}
let [x = f()] = [1];//不执行f(),因为给x赋值1了
let [x = f()] = [];//执行
默认值可以引用解构赋值的其他变量,但是该变量必须已经声明
let [x=1,y=x] = []; //x=1;y=1;
let [x=1,y=x] = [2]; //x=2;y=2;
let [x=y,y=1] = []; //ReferenceError
对象的解构与数组的解构有一个重要的不同;数组的元素是按次序排列的,变量的取之由他的位置决定;而对象的属性是没有次序的,变量必须与属性同名,才能取到正确的值
let {bar,foo} = {foo:"aaa",bar:"bbb"};
bar // bbb
foo //aaa
let {baz,foo} = {foo:"aaa",bar:"bbb"};
baz //undefined
如果变量名与属性名不一致
let {first:f, last:l} = {first:"hello", last:"bye"};
first //undefined
f //hello
last //undefined
l //bye
实际上对象解构赋值是以下形式的简写
let {bar:bar,foo:foo} = {foo:"aaa",bar:"bbb"};
也就是说对象解构赋值的内部机制,是先找到同名属性,然后在赋值给对应的变量,真正被赋值的是后者,而不是前者
let foo;
let {foo} = {foo:"haha"};
//Uncaught SyntaxError: Identifier 'foo' has already been declared
解构嵌套对象
let {loc: {start: { line }}} = {
loc: {
start: {
line:1,
column:5
}
}
}
line //1
注意:只有line是变量,loc和start都是模式,不会被赋值
对象的解构也可以指定默认值,默认值生效的条件是,对象的属性严格等于undefined
let {x = 3,y = 1,z = 2} = {x: undefined,y: 6,z: null};
x //3
y //6
z //null
解构模式是嵌套的对象,而自对象的赋属性不存在,那么将会报错
let {foo:{bar}} = {baz:"aaa"};
//Cannot destructure property `bar` of 'undefined' or 'null'.
原因很简单,因为foo这时等于undefined,再取子属性就会报错;
将一个已经声明的变量用于解构赋值
//错误写法
let x;
{x} = {x:1};
//Uncaught SyntaxError: Unexpected token =
因为JavaScript引擎会将{x}理解成一个代码块,从而发生语法错误;
只有不将大括号写在首行,避免JavaScript将其解释成代码块,才能解决这个问题。
//正确写法
let x;
({x} = {x:1});
解构赋值时,若果右边是数值或者布尔值,则会先转成对象
let {toString:s} = 123;
s === Number.prototype.toString //true
let {toString:s} = true;
s === Boolean.prototype.toString //true
对于undefined和null无法转为对象,所以对他们解构赋值就会报错
let {prop:x} = undefined;
let {prop:x} = null;
//Uncaught TypeError: Cannot destructure property `prop` of 'undefined' or 'null'.
不能使用圆括号的情况:
1. 变量声明语句中,模式不能带有圆括号
let [(a)] = [1];
let {x:(c)} = {};
let {o:({p:p})} = {o:{p:2}};
//全部报错
//Uncaught SyntaxError: Unexpected token (
function f([(a)]){return a;}
//Uncaught SyntaxError: Unexpected token (
//全部报错
({p:a}) = {p:42};
([a]) = [5];
将整个模式放在了圆括号中了,导致报错。
//报错
[({p:a}),{x:c}] = [{},{}];
将嵌套模式的一层放在圆括号中了
可以使用圆括号的情况
赋值语句的非模式部分可以使用圆括号
[(b)] = [3];//正确
({p:(d)} = {});//正确
[x,y] = [y,x]
//参数是一组有序的值
function f([x,y,z]) {...};
f([1,2,3]);
//参数是一组无序的值
function f({x,y,z}) {...};
f({z:3,x:1,y:2});
传统上,JavaScript中只有indexOf方法可以来确定一个字符串是否包含在另一个字符串中;
ES6新增三种:
- includes():返回布尔值表示是否找到了参数字符串
- startsWith():返回布尔值,表示参数字符串是否在源字符串的头部
- endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部
这三个方法都支持第二个参数 表示开始搜索的位置
let t = "hello world";
t.includes("e",4);//false
repeat方法返回一个新的字符串,表示将原字符串重复n次。
"hello".repeat(3); //hellohellohello
"hello".repeat(0); //""
如果是小数,会取整
"hello".repeat(2.7); //hellohello
如果是负数或者Infinity,会报错
"hello".repeat(-2);//Uncaught RangeError: Invalid count value
"hello".repeat(Infinity); //Uncaught RangeError: Invalid count value
如果是0到-1之间的小数,则等同于0,因为先进行取整计算,0到-1取整是-0,repeat视为0
"hello".repeat(-0.8); //""
参数NaN等同于0
"hello".repeat(NaN); //""
如果repeat参数是字符串,则会先转换成数字
"hello".repeat("he"); //""
"hello".repeat("2"); //"hellohello"
padStart用于头部补全
padEnd用于尾部补全
x.padStart(5,"ab");//ababx
x.padStart(4,"ab");//abax
x.padEnd(5,"ab");//xabab
x.padEnd(4,"ab");//xaba
第一个参数指定字符串长度,第二个参数是用来补全的字符串
如果源字符串长度大于指定的最小长度,则返回源字符串
xxx.padEnd(2,"ab");//xxx
如果第二个参数省略,则用空格补全
x.padEnd(3);//' x'
x.padEnd(3);//'x '
模版字符串是增强版的字符串,用反引号(`)标识;他可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量
let name="Tom",time="today";
`hello ${name},how arw your ${time}`
大括号里面可以放任意的JavaScript表达式,可以进行运算,以及引用对象属性。
let x = 1;
let y = 2;
`${x}+${y}=${x+y}`//1+2=3
let obj = {x:1,y:3};
`${obj.x+obj.y}`
// 4
模版字符串中还能调用函数
function fn(){
return "hehe";
}
`test ${fn()}`
// test hehe
如果模版字符串中的变量没有声明,会报错