带你深入了解es6中的解构赋值

6 篇文章 0 订阅
4 篇文章 0 订阅

解构赋值

什么是解构赋值
顾名思义,解构赋值就是将集合中的值提取出来,再对变量进行赋值,其实就是返回的一个遍历器对象(Iterator),如果赋值右边不是可遍历的结构就会报错

  • 数组的解构
	let foo = 1;
	let bar = 2;
	let test = 3;
	// 以前的赋值方式
	let [foo, bar, test] = [1, 2, 3]
	// 用了数组结构之后
数组的解构赋值,会按照位置依次赋值
	let [foo, bar, car] = ['foo'];
	// bar和car会变为undefined, 因为解构失败
	let [foo, bar, ...car] = ['foo'];
	// bar还是undefined 但是此时car为一个空数组
	let [foo, ...bar] = [1, 2, 3, 5, 6];
	// foo只会占据一位,bar会把剩下的位置全部占用并且赋值形成一个新数组
如果解构失败那么就会返回undefined
	let [foo] = [];
	let [bar, foo] = [1];
	// 以上foo都会返回undefined
	```
	还有一种不完全解构
	```javascript
	let [foo, bar] = [1, 4, 9];
	let [foo, [car, wife], bar] = [1, [5, 7, 9], 10];
	// 上面依旧可以解构成功,没有赋值的值会留原数组中,以便后续使用
事实上,只要某种结构具有遍历器对象Iterator就可以采用数组的解构赋值

解构赋值可以采用default默认值的写法,它采用赋值右边完全等于undefined时才会触发
	let [foo = 1] = [];
	
	let [x, y = 'foo'] = ['bar'];
	// x = 'bar' y = 'foo';
	let [x, y = 'foo'] = ['bar', undefined];
	// x = 'bar' y ='foo'; 由于y传了undefined所以遵循===规则使用默认值
默认值还可以使用已经声明的值
	let [foo = 1, bar = foo] = [undefined, undefined];
	// foo = 1, bar = 1; bar使用了foo的变量且传值是undefined,所以都是1
	let [foo = 1, bar = foo] = [2];
	// foo = 2, bar = 2; 由于传值不是undefined所以foo使用2,bar又等于foo
	let [foo = 1, bar = foo] = [1, 2];
	// foo = 1, bar = 2; 由于俩值都穿了值,所以就不存在使用默认值了,直接赋值
	let [foo = bar, bar = 1] = [];
	// error 因为bar还没有定义呢,你就是用就会报错
  • 对象的解构

解构赋值,既可用于数组又可用于对象

	let {bar, foo} = {bar: 'bar', foo: 'foo'};
	// bar: 'bar', foo: 'foo'

数组采用索引来赋值,而对象没有这种机制,赋值变量必须与属性值相同才能赋值

	let {foo, bar} = {bar: 'bar', foo: 'foo'}
	// bar: 'bar'
	// foo: 'foo'
	
	let {baz} = {bar: 'foo', foo: 'bar'}
	// baz: undefined

首先上述例子是对象解构,所以不会运用索引机制,他会先看属性名和变量名是否一致,并且是否拥有,紧接着把属性变量名相同的进行赋值

上述两个例子,虽然第一个变量顺序和属性不符,但是对象的机制就是观察是否相同,不会去管索引(对象中就没有索引),紧接着第二个因为没有相同属性值,所以变量baz赋值不成功,结果undefined!

结构失败,变量为undefined

	let {name} = {sex: 'male'}
	// name: undefined

等号右边属性中没有name,所以解构不成功,值为undefined

js内部的对象也可以解构

	let {log, sin, cos} = Math;
	let {log. dir} = console;
	let {write} = document;
	log('hello, es6');
	// 对于js中现有对象都可以采用这种解构,来缩写代码的占用(说白了,有时候可以懒一下)

变量与属性不一致时,需采用以下写法

	let {bar: baz} = {bar: 'bar', foo: 'foo'}
	// baz: 'bar'
	let obj = {first: 'hello', last: 'world'}
	let {first: f, last: l} = obj;
	// f: 'hello'
	// l: 'world'
	
	// 上述就等于
	let {first: f, last: l} = {first: 'hello', last: 'world'}
	// f: 'hello'
	// l: 'world'

实际对象结构是这样的机制

	let {foo: foo, bar: bar} = {foo: 'foo', bar: 'bar'}
	// foo: 'foo'
	// bar: 'bar'

也就是说,对象的解构赋值内部机制,是先找到同名属性,再赋给对应的变量,真正被赋值的是后者,而不是前者

下面来验证这个说法

	let {bar: baz} = {bar: 'foo', foo: 'bar'}
	// baz: 'foo'
	// bar: error: bar is not defined

上述代码bar只是模式,而baz才是变量,被赋值的是baz

对象解构也可以进行嵌套

	let obj = {
		target: [
			'son',
			{
				person: 'person'
			}
		]
	}
	
	let { target: [x, {y}] } = obb;
	// x: 'son'
	// y: 'person'
	// target: error : target is not defined
	

此时的target只是模式

下面这种写法可以使target变为变量

	let obj = {
		target: [
			'son',
			{
				person: 'person'
			}
		]
	}
	
	let { target, target: [x, {y}] } = obj;
	// x: 'son'
	// y: 'person'
	// target: ['son', {person: 'person'}]
	

再来看另一个例子

	let obj = {
		person: {
			son: {
				car: 'BMW',
				money: 'Infinty'
			}
		}
	}

	let { person, person: {son}, person: { son: {car} } }
	/* person: {
			son: {
				car: 'BMW',
				money: 'Infinty'
			}
		}
	*/
	/* son: {
			car: 'BMW',
			money: 'Infinty'
		}
	*/
	// car: 'BMW'

第二个person和第三个person与son都是模式,真正被解构的是在花括号里的值

	let obj = {}
	let arr = []

	let { foo: obj.prop, bar: arr[0] } = {prop: 'show', bar: true}
	// obj: {prop: 'show'}
	// arr: [true]

下面这种会报错

	let { foo: {bar} } = {baz: 'baz'}
	// error

原因是foo不存在,所以子对象取值会报错

	let obj1 = {}
	let obj2 = {foo: 'bar'}
	Object.setPrototypeof(obj1, obj2);
	// 此时obj2就是obj1的原型
	let {foo} = obj1;
	// 解构赋值可以拿到原型属性

解构赋值可以拿到原型属性

与数组一样,对象也可以有默认值

	let {x = 1, y = 2} = {x: undefined,y: 5}
	// x = 1
	// y = 5

也就是说对象也采用了等号右边严格等于(===)undefined,默认值生效

	let {x = 3} = {x: undefined}
	let {y = 2} = {y: null}
	// x = 3
	// y = null

null不严格等于undefined所以不能使用默认值

如果一个变量已声明,不该再用于结构

	let x;
	{x} = {x: 1};
	// 此时的{x}被js理解我一个代码块去执行,所以会报错
	({x} = {x: 1});
	// 此时为立即执行,不会报错

等于左边可以不放变量来进行赋值,但没有意义

	({} = [true, false]);
	({} = 'abc');
	({} = []);

数组是本质是特殊的对象,所以可以对数组进行对象形式解构

	let arr = [1, 2, 3];
	let {0: first, [arr.length - 1]: last} = arr;
	// first = 1
	// last = 3
	

first代表数组的第0位,所以就是1,length - 1是第二位,所以last就是3
[arr.length - 1]属于属性名表达式

  • 字符串的解构赋值

在解构的时候,字符串会被转换成类数组对象
拥有length属性

	let [w, o, r, l, d] = 'hello';
	// w = h
	// o = e
	// r = l
	// l = l
	// d = o

并且可以获取length属性

	let [length: len] = 'hello,es6';
	// len: 9
  • 数值和布尔的解构

    如果等号右边的值不是数组,对象就会先进行转换,转换为对象,来进行赋值

	// 会先调用包装类,把123转换为对象
	let {tostring: s} = 123;
	let {tostring: s} = { value: 123, tostring: fn(){} }
	// 所以s可以获取到原型上tostring的方法
	s === Number.prototype.tostring

	// boolean同上
	let {tostring : b} = false;
	let {tostring : b} = {value: false, tostring: fn(){}}
	b === Boolean.prototype.tostring

这种解构的规定就是,如果不是对象或数组就先转换为对象,如果转不了就报错,如null,undefined

	let {prop: foo} = null;
	let {prop: bar} = undefined;
	// 以上都会报错
  • 函数参数解构
	function test ([x, y]) {
		return x + y
	}
	
	test([1, 9])
上述看起来就是实参与形参的传递,但在传入数组的一刻就已经进行解构了
	[[1, 2], [3, 4]].map( ([a, b]) => a + b )
	// 此时[1, 2]就是a [3, 4]就是b被依次解构到一个新数组中

同样函数参数也可以使用默认值

	function test ({x = 0, y = 0} = {}) {
		return [x, y]
	}
	test({x: 1, y: 2}) // [1, 2]
	test({x: 3}) // [3, 0]
	test({}) // [0, 0]
	test() // [0, 0]
	// 第一种显而易见都传值了
	// 第二种只传了x所以y是默认值
	// 第三种由于传了空对象,所以返回的结果是默认值
	// 第四章什么都没有传,所以严格等于undefined,使用默认值

还有一个例子,给函数参数设置默认值,而不给变量x,y设置

	function person ({x, y} = {x: 0, y: 0}) {
		return [x, y]
	}
	
	// 此时的x,y没有默认值,因为设置的默认值是{x, y} = {x: 0, y: 0},
	// 而不是{x = 0, y = 0} = {},它是在给{x, y} 这个参数在设置默认值,
	// 所以x , y 是undefined,所以会有以下结果.
	person({x: 3, y: 5}) // [3, 5]
	person({x: 3}) // [3, undefined]
	person({}) // [undefined, undefined]
	person() // [0, 0]
	// 以上都没有难度
	// 最后一个为什么是[0, 0] 而不是[undefined, undefined]
	// 由于你没传任何值,{x, y}这个参数会使用默认值{x: 0, y: 0},所以返回[0, 0]

由于undefined会触发函数参数默认值

	[1, undefined, 5].map( (x = 'foo') => x)
	// [1, 'foo', 5]

为什么要用解构赋值
1. 交换两个值
在以前可能要声明变量运用一些手法交换值

	let a = 100;
	let b = 200;
	// 第一种
	let c = a + b;
	let a = c - a;
	let b = c - b;
	// 第二种
	let a = a + b;
	let b = a - b;
	let a = a - b;
	// 第三种, 也就是解构赋值的交换
	[a, b] = [b, a];
	// so easy to Happy啊
  1. 函数返回多个值
	// 数组
	function test () {
		return [1, 2, 3]
	}
	let [a, b, c] = test();

	// 对象
	function show () {
		return {
			car : 'BMW',
			wife : 'xiaofan'
		}
	}
	let [car, wife] = show();
	
  1. 函数参数的定义
	// 有序的数组
	function person ([x, y, z]) {
		return [x, y ,z]
	}
	person([1, 2, 3])
	
	// 无序的对象
	function son ({x = 0, y = 1, z = 2}) {
		return {x, y, z
		}
	}
	son({x: 1, y: 3, z: 9})
  1. 提取json
	let json = {
		"name" : "xiaoming",
		"age" : 20,
		"sex" : "male"
	}

	let [id, age, sex: girl] = json;
	// id = "xiaoming", age = 20, girl = "male"
  1. 函数参数默认值
	function ajax ({method = 'get', async = 'async', foo = 'foo'} = {}) {
		
	}
	// 无需再初始化变量 let foo = 'foo'这种
  1. 遍历map结构
	let map = new Map();
	map.set('car': 'BMW');
	map.set('wife': 'xiaofan');
	// 获取键值
	for (let [key, value] of map){
		console.log(key + ':' + value);
	}
	// 只获取键
	for (let [key] of map){
		console.log(key);
	}
	// 只获取值
	for (let [, value] of map){
		console.log(value);
	}
	// 因为这里第一个参数就是键,所以需要都好来填充,使其变为undefined
	
	
  1. 加载模块
	import React,{ Component } from 'React';
	// 上面就等于下面这样
	import React from 'React';
	const Component = React.Component;

解构带来了那些方便

都写这么多了还不够方便你的书写? 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值