ES6学习——新的语法:对象解构(Object Destructuring)

73 篇文章 23 订阅

解构在ES6中应该是一种新的语法,在其他语言中我没怎么见到这种语法,也可以说是赋值操作的另一种形式,因为解构的整个定义都在规范的赋值操作符章节下面,有兴趣的可以看规范的12.14.5。目前浏览器对这个新语法的支持还不是很好,但是Firefox 43已经支持了大部分解构特性,这里我们仍然继续使用Kinoma Studio来测试代码。

这篇文章主要讲对象的解构赋值操作,先看个简单的例子有点印象:

let obj = { first: 'Jane', last: 'Doe' };
		
let { first: f, last: l } = obj;//仔细看这里,我们习惯赋值是右侧表达式赋值给左侧表达式,但解构却是从左侧赋值给右侧
		
trace(f + " " +l);//Jane Doe

let f = obj.first,l = obj.last//旧的写法

这个简单的例子可能看不出来这种语法的必要性,先不要着急,我们先弄清一个问题,在解构赋值的右侧,也就是右侧表达式,可以是什么?在规范的12.14.5.2章节中有如下的描述:

ObjectAssignmentPattern : { } 

1. Let valid be RequireObjectCoercible(value). 

2. ReturnIfAbrupt(valid). 

3. Return NormalCompletion(empty). 


从上面的描述中可以清晰的看到,需要右侧的表达式可以转换成对象,在有兴趣的可以继续看RequireObjectCoercible方法是怎么定义的,这里就不在继续解释了,我们可以记住除了null和undefined都可以转成对象形式,即使是字面量,像:2,"123",true等。下面看个例子:

let {length : len} = 'abc'; // len = 3
let {toString: s} = 123; // s = Number.prototype.toString
		
trace(len+"\n");//3
trace(s);//[object Function]

let { prop: x } = undefined; // # Exception: run: cannot coerce undefined to object!
let { prop: y } = null; // # Exception: run: cannot coerce undefined to object!

接着看两个例子,说明其他特点:

let obj = { a: [{ foo: 123, bar: 'abc' }, {}], b: true };
let { a: [{foo: f}] } = obj; //深层嵌套赋值
		
let { x: x } = { x: 7, y: 3 ,z:6};//只取x的值
		
trace(f);//123
trace(x);//7

解构操作还有一种更简单的写法,如果需要赋值的变量名和对象的属性名称一样,可以写成下面这样:

let { x, y } = { x: 11, y: 8,z:6 };
trace(x + " " + y);//11 8

其实我们在左侧可以使用计算属性的特性,计算属性是Object Literal Extensions章节要讲的内容,这里先大概了解一下:

const FOO = 'foo';
let { [FOO]: f } = { foo: 123 }; // f = 123
//FOO可以是变量

上面的例子中左侧都是声明变量并初始化的形式,那么左侧可不可以直接给变量赋值呢?答案肯定是可以的,但要注意形式:

let x,y,obj = { x: 7, y: 3 };

//{x,y} = obj;//语法错误,大括号里面会被当成复合语句。这里需要记住
	
({x,y} = obj);


我们在用eval函数处理JSON字符串的时候也会有这个问题,所以需要加上小括号才行:eval('('+json+')'),道理一样。还有一个问题是重复声明的语法错误,需要注意:

let x;
let { x, y } = { x: 11, y: 8 };//注意这里会有语法错误,报重复声明x变量

下面说一个我在使用Kinoma中遇到的一个解构的问题:
var o = {};
({x:o.x,y:o.x,z:o.z} = {x:2,y:4,z:5});
//这种写法在规范中应该是可以的,但是在Kinoma中总是报no reference错误,无法执行。我换了Firefox 43进行测试,上面的写法是OK的。

还有一点要注意,上面是先声明了变量o,然后在进行解构赋值。如果我们直接声明并初始化的形似:
var {x:o.x} = {x:2};//这里会报错,并不会把o先声明成对象,然后在进行解构

下面我们看一个连续赋值的问题:

var o = { a:1, b:2, c:3 },
a, b, c, p;
p = {c} = {a,b} = o;
trace( a + " " + b + " " + c); // 1 2 3
trace(p === o);//true

上面的例子说明了解构操作不会影响变量的连续赋值,最终p是严格等于o的。


解构操作还有一个特性,就是可以有默认值:

let {foo: x=3, bar: y} = {}; // x = 3; y = undefined

let {prop: y=2} = {prop: undefined}; // y = 2

function log(x) { trace(x+"\n"); return'YES'}
let {x:a = log(4)} = {x:0};
trace(a);//'YES',注意这里默认值的处理和规范不一样,具体参考函数参数默认值那篇文章,firefox和chrome下是0

//基本上函数参数默认值的那些特性都可以应用在这里。应用默认值的时候不要写的太复杂,否则很难看懂,像下面例子这样:

var x = 200, y = 300, z = 100;
var o1 = {x: { y: 42 }, z: { y: z } };

({ y: x = { y: y } } = o1);//o1没有y属性,所以x被赋与默认的对象,默认对象中有个y属性,值为全局变量y的值
({ z: y = { y: z } } = o1);//把o1摸z属性赋值给y.y,值是全局变量z
({ x: z = { y: x } } = o1);//把o1的x属性赋给z.y,值为o1.x.y

trace( x.y + " " + y.y + " " + z.y ); // 300 100 42



最后看个简单的例子,查找数组元素第一个为偶数的数值和位置:

		function findArray(arr,cb){
			for(let i=0;i<arr.length;i++){
				if(cb(arr[i])){
					return {ele:arr[i],index:i};
				}
			}
			return {ele:undefined,index:-1};
		}
		
		let arr = [21,3,5,6,7],cb = function(ele){return ele % 2 == 0};
		
		
		let {ele,index} = findArray(arr,cb);
		trace(ele + " " + index);
                let {index:idx} = findArray(arr,cb);

解构这种用法在一些情况下确实会简单化代码,大家可以在ES6得到应用的时候大胆使用解构赋值。


*以上代码全部在Kinoma Studio中通过测试

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值