es6 基础笔记(一)let 和const命令\变量的解构赋值

let 和const命令

1、let命令

let用来声明变量,但作用范围只在命令所在的代码块内有效。
for循环的计数器,很适合使用let命令
for(let i=0;i<10;i++)
{}
let使用必须在声明之后,否则报错。var则不需要遵守此规则。

2、const命令
声明一个只读的常量,一旦声明值就不能改变,声明时就要赋值,重新赋值会报错。
例如:const max=5;
const message=“hello!”;
另一点,如果存储的是复合类型的数据,存储的其实是数据的地址。
例如:const foo={};
foo.prop=123;

const a=[];
a.push(‘hello’);
这样是不会报错的,因为存储的地址没变,也就是说数据是改变了的,所以使用时要注意。
如果真想将对象冻结,应该使用Object.freeze方法。
例如:const foo=Object.freeze({});
foo.prop=123;//常规模式时,执行不起作用;严格模式时,执行会报错。

除了将对象跟本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。
下面展示一些 内联代码片

// An highlighted block
var const antize=(obj)=>{
	Object.freeze(obj);
	Object.keys(obj).forEach((key,i)=>{
		if(typeof obje[key]==='object'){
			constantize(obj[key]);
		}
	});
};

ES6的六种声明变量方法:var、let、const、import、function、class

3、顶层对象的属性
顶层对象,在浏览器环境指的是window对象,在Node指的是global对象。
例如:
window.a=1;
顶层对象的属性赋值与全局变量的赋值,是同一件事。

两个获取顶层对象的方法

下面展示一些 内联代码片

// An highlighted block
(typeof window !=='undefined' 
	? window:
	(typeof process === 'object' &&
	typeof require ==='function' &&
	typeof global ==='object')
	 ? global 
	 : this);

// An highlighted block
var getGlobal=function(){
	if(typeof self !== 'undefined') {return self;}
	if(typeof window !== 'undefined') {return window;}
	if(typeof global !== 'underfined') {return global}
	throw new Error('unable to locate global object');
};

变量的解构赋值

1、数组的解构赋值
匹配模式:let [a,b,c]=[1,2,3];
嵌套数组进行结构:
下面展示一些 内联代码片

// An highlighted block
let [foo,[[bar],baz]]=[1,[[2],3]];
foo//1
bar//2
baz//3

let [,,third]=["foo","bar","baz"];
third//"baz"
let [x,,y]=[1,2,3];
x//1
y//3

let [head,...tail]=[1,2,3,4];
head//1
tail//[2,3,4]

let [x,y,...z]=['a'];
x//"a"
y//undefined
z//[]

解析不成功,变量值就等于undefined。
例如:
下面展示一些 内联代码片

// An highlighted block
let [foo]=[];
let [bar,foo]=[1];

以上foo都等于undefined。

还有另一种情况,不完全结构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,结构依然可以成功。

// An highlighted block
let [x,y]=[1,2,3];
x//1
y//2

let [a,[b],d]=[1,[2,3],4];
a//1
b//2
d//4

如果等号的右边不是数组(或者严格地说,不是可比案例的结构),那么将会报错
//报错

// An highlighted block
let [foo]=1;
let [foo]=false;
let [foo]=NaN;
let [foo]=undefined;
let [foo]=null;
let [foo]={};

对于Set结构,也可以使用数组的结构赋值。

// An highlighted block
let [x,y,z]=new Set(['a','b','c']);
x//"a"

事实上,只要某种数据结构具有Interator接口,都可以采用数组形式的结构赋值。
例如:

// An highlighted block
function *fibs(){
	let a=0;
	let b=1;
	while(true){
		yield a;
		[a,b]=[b,a+b];
	}
}
let [first,second,third,fourth,fifth,sixth]=fibs();
sixth//5

fibs 是一个Generator函数,原生具有Iterator接口。结构赋值会一次从这个接口获取值。

默认值
结构赋值允许指定默认值。

// An highlighted block
let [foo=true]=[];
foo//true

let [x,y=‘b’]=[‘a’];//x=‘a’,y=‘b’
let [x,y=‘b’]=[‘a’,undefinde];//x=‘a’,y=‘b’
注意,ES6内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会剩下。

// An highlighted block
let [x=1]=[undefined];
x//1

let [x=1]=[null];
x//null

上面代码,如果一个数组成员是null,默认值就不会剩下,因为null不严格等于undefined。

如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。

// An highlighted block
function f(){
	console.log('aaa');
}
let [x=f()]=[1];

上面代码中,因为x能取到值,所以函数f根本不会执行。上面的代码其实等价于下面的代码。

// An highlighted block
let x;
if([1][0]===undefined){
	x=f();
}else{
	x=[1][0];
}

默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

// An highlighted block
let [x=1,y=x]=[];//x=1,y=1
let [x=1,y=x]=[2];//x=2;y=2
let [x=1,y=x]=[1,2];//x=1;y=2
let [x=y,y=1]=[];//ReferenceError:y is not defined

上面最后一个表达式之所以会报错,是因为x用y作为默认值时,y还没有声明。

2、对象的结构赋值
结构不尽可以用于数组,还可以用于对象。

// An highlighted block
let {foo,bar}={foo:'aaa',bar:'bbb'};
foo//"aaa"
bar//"bbb"

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性名,才能取到正确的值。

// An highlighted block
let {bar,foo}={foo:'aaa',bar:'bbb'};
foo//"aaa"
bar//"bbb"
let{baz}={foo:'aaa',bar:'bbb'};
baz//undefined

第一个例子,等号左边的两个变量的次序,与等号右边两个同名属性的次序不一致,但是对取值完全没影响。第二个例子的变量没有对应的同名属性,导致取不到值,最后等于undefined。

默认值
对象的二结构也可以制定默认值

// An highlighted block
var {x=3}={};
x//3

var {x,y=5}={x:1};
x//1
y//5

var {x:y=3}={};
y//3

var {x:y=3}={x:5};
//y//5
var {message:msg='Something went wrong'}={};
msg//Something went wrong

默认值生效条件是,对象的属性值严格等于undefined。

// An highlighted block
var {x=3}={x:undefined};
x//3

var {x=3}={x:null};
x//null

注意点
//错误写法
let x;
{x}={x:1}
//x会被理解称为一个代码块,发生语法错误

//正确写法
let x;
({x}={x:1});

解构赋值允许等号左边的模式中,不放置任何变量名。
({}=[true,false]);
({}=‘abc’);
({}=[]);

由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
let arr=[1,2,3];
let {0:first,[arr.length-1]:last}=arr;
first//1
last//3

3、字符串的结构赋值
字符串赋值

// An highlighted block
const[a,b,c,d,e]='hello';
a//"h"
b//"e"
c//"l"
d//"l"
e//"o"

4、数值和布尔值的解构赋值
解构赋值时,等号右边是数值和布尔值,则会先转为对象。

// An highlighted block
let {toString:s}=123;
s===Number.prototype.toString//true

let {toString:s}=true;
s===Boolean.prototype.toString//true

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和ull无法转为对象,所以对它们进行结构赋值,都会报错。
let {prop:x}=undefined;//TypeError
let {prop:y}=null;//TypeError

5、函数参数的解构赋值
函数的参数也可以使用解构赋值。
例:

// An highlighted block
function add([x,y]){
	return x+y;
}
add([1,2]);//3

上面代码,函数add的参数表面上时一个数组,但在传入参数的那一刻,数组参数就被解构成变量x和y。对于函数内部的代码来说,它们能感受到的参数就是x和y。
另一个例子:

// An highlighted block
[[1,2],[3,4]].map(([a,b])=>a+b);

函数参数的结构可以使用默认值

// An highlighted block
function move({x=0,y=0}={}){
	return [x,y];
}
move({x:3,y:8});//[3,8]
move({x:3});//[3,0]
move({});//[0,0]
move();//[0,0]

下面的写法会得到不一样的结果。

// An highlighted block
function move({x,y}={x:0,y:0}){
	return [x,y];
}
move({x:3,y:8});//[3,8]
move({x:3});//[3,undefined]
move({});//[undefined,undefined]
move();//[0,0]

上面代码是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到不一样的结果。

undefined会出发函数参数的默认值。
[1,undefined,3].map((x=‘yes’)=>x);//[1,‘yes’,3]

6、圆括号的问题
解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。
由此带来的问题是,如果模式中出现圆括号怎么处理。ES6 的规则是,只要有可能导致解构的歧义,就不得使用圆括号。
但是,这条规则实际上不那么容易辨别,处理起来相当麻烦。因此,建议只要有可能,就不要在模式中放置圆括号。
不使用圆括号的情况
以下三种解构赋值不能使用圆括号
变量生命语句
//全部报错
let [(a)]=[1];
let {x:©}={};
let ({x:c})={};
let {{x:c}}={};
let {(x):c}={};
let {o:({p:p})}={o:{}p:2}};

函数参数
函数参数也属于变量生命,不能带有圆括号。
//报错
function f([(z)]){return z;}
//报错
function f([z,(x)]) {return x;}

赋值语句的模式
//全部报错
({p:a})={p:42};
([a])=[5];
[({p:a}),{x:c}]=[{},{}];

可以使用圆括号的情况
使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用。
[(b)]=[3];
({p:(d)}={});
[(parseInt.prop)]=[3];

7、用途
交换变量的值
let x=1;
let y=2;
[x,y]=[y,x];
上面代码交换变量x和y的值,这样的写法不仅简洁,而且易读,语义非常清晰。

从函数返回多个值
函数智能返回一个值,如果要返回多个值,智能将它们放在数组或对象里返回。有了解构赋值,去除这些值就非常方便。
//返回一个数组
function example(){
return [1,2,3];
}
let [a,b,c]=example();
//返回一个对象
function example(){
return{
foo:1,
bar:2
};
}
let {foo,bar}=example();

函数参数的定义
解构赋值可以方便地将一组参数与变量名对应起来。
//参数是一组有次序的值
function f([x,y,z]){…}
f([1,2,3]);

//参数是一组无次序的值
function f({x,y,z}){…}
f({z:3,y:2,x:1});

提取JSON数据
解构赋值对提取JSON对象中的数据,尤其有用。
let jsonData={
id;42,
status:“OK”,
data:[867,5309]
};
let {id,status,data:number}=jsonData;
console.log(id,status,number);//42,“OK”,[867,5309]
上面代码可以快速提取JSON数据的值。

函数参数的默认值
jQuery.ajax=function (url,{
async=true,
beforeSend=function(){},
cache=true,
complete=function(){},
crossDomain=false,
global=true,
//…more config
}={}){
//…do stuff
}

遍历Map结构
任何部署了Iterator接口的对象,都可以用for…of循环遍历。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便了。
const map=new Map();
map.set(‘first’,‘hello’);
map.set(‘second’,‘world’);
for(let [key,value] of map){
console.log(key+" is "+ value);
}
//firest is hello
//second is world

如果只想获取键名或键值,可以这样写
//获取键名
for(let [key] of map)
{}
//获取键值
for(let [,value] of map)
{}

输入模块的制定方法
加载模块时,往往需要制定输入哪些方法。解构赋值使得输入语句非常清晰。
const {SourceMapConsumer,SourceNode}=require(“source-map”);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值