JS中的解构

**声明:**文章取自 疯狂的技术宅 前端栈 晴朗的树 本文是根据前辈的内容加以学习记录。

变量的解构使用

变量的解构主要应用于读取访问,操作部分属性或值。下面是5个常用的变量解构操作。

1、交换变量

​ 通常交换两个变量,我们会以一个中间变量来进行值的传递。这里实例的是一个简单的原始值类型,如果切换为引用值类型时候,思路是一样的。原因就在于引用值类型的变量是一个堆中的地址值,实际保存的值在栈中,系统为其分配的内容不会变化,我们在交换变量的时候,只是改变了指向的位置。

let a = 1;
let b = 2;
let temp;

temp = a;
a = b;
b = temp;

a; // => 2
b; // => 1

解构分配使变量交换变得简单,不需要任何临时变量:

let a = 1;
let b = 2;

[a, b] = [b, a];

a; // => 2
b; // => 1

临时在右侧构建出一个数组,存放[2,1],分别将数组中的第一项和第二项赋值给a,b。使用这种方式进行数据交换最好的地方就是:简洁,可以根据需要交换任意多个变量!至于内存回收,js自己会对不用的变量内存回收。

2、访问数组项

如果对于一个不确定的数组或其他结构类型数据,我们要获得它的某个元素,如果不存在就赋予变量默认值,通常的做法是根据该数组(结构)的.length来进行判断。

const colors = [];

let firstColor = 'white';
if (colors.length > 0) {
 firstColor = colors[0];
}

firstColor; // => 'white'

数组解构是这样做的

const colors = [];

const [firstColor = 'white'] = colors;

firstColor; // => 'white'

const [firstColor =‘white’] = colors 解构将 colors 数组的第一个元素分配给firstColor 变量。如果数组在索引 0 处没有任何元素,则将分配默认值 white 。如果你只想访问第二个元素,也可以这样:

const colors = [];

const [, secondColor = 'black'] = colors;

secondColor; // => 'black'

注意结构左侧的逗号:这意味着第一个元素将被忽略。从 color 数组中为索引为 1 的元素分配了 secondColor。

相较于Array中获取数组中的部分元素 slice()方法,我们可以添加默认值。

3、不变的操作

从原数组中抽取子集数组,而上面的案例是抽取某一个元素。

const numbers = [1, 2, 3];

const [, ...fooNumbers] = numbers;

fooNumbers; // => [2, 3]
numbers; // => [1, 2, 3]

解构 [, …fooNumbers] = numbers 将创建一个新的数组 fooNumbers,其中包含除了第一项外的所有元素。numbers 数组不会发生变异,从而使操作保持不变。

除了这样操作数组,我们还可以将结构应用于对象属性上,…small解构赋值,small的数据类型取决于被解构对象,即与等号右边的变量类型保持一致,Object是实现了iterator协议的数据类型,所以可以迭代,…返回的是对象中的每一个属性,属性名自动适配右侧中的属性,组合起来就是删除了foo属性的对象。

const big = {
 foo: 'value Foo',
 bar: 'value Bar'
};

const { foo, ...small } = big;

small; // => { bar: 'value Bar' }
big; // => { foo: 'value Foo', bar: 'value Bar' }

需要注意的是我们在删除对象中的部分属性时候,需要知道属性名才可以,类似于一个一一映射关系。

			const big = {
			 foo: 'value Foo',
			 bar: 'value Bar'
			};
			const { foo1, ...small } = big;
			console.log(small)//{foo: 'value Foo', bar: 'value Bar'}
4、解构可迭代对象

在前面,我们将解构应用于数组。但是你可以解构实现了可迭代协议的任何对象。许多原生原始类型和对象都是可迭代的:数组、字符串、类型化数组、集合和映射。例如,你可以将字符串分解为字符:

			const str = 'cheese';
			const [...first] = str;
			const [seconde] = str;
			console.log(first);//['c', 'h', 'e', 'e', 's', 'e']
			console.log(seconde);//c

不仅限于原生类型,也可以通过实现可迭代协议来自定义解构逻辑。

const movies = {
  list: [
    { title: 'Heat' }, 
    { title: 'Interstellar' }
  ],
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        if (index < this.list.length) {
          const value = this.list[index++].title;
          return { value, done: false };
        }
        return { done: true };
      }
    };
  }
};

const [firstMovieTitle] = movies;
console.log(firstMovieTitle); // => 'Heat'

movies 对象通过定义 Symbol.iterator 方法来实现可迭代的协议。迭代器遍历电影的标题。遵循可迭代协议,可以将 movies 对象结构为标题,特别是通过读取第一部电影的标题:const [firstMovieTitle] = movies。

5、解构动态属性

通过属性对对象进行解构比对数组进行解构更为常见。

const movie = {
				title: 'Heat'
			};
			const movie1={
				
			};
			const {
				title = "hhh"
			} = movie;
			const {
				title1 = "hhh"
			} = movie;
			const{title2="123"}=movie1;
			console.log(title);//Heat
			console.log(title1);//hhh
			console.log(title2);//123

类似于键值对的解构,通过键可以从对象中拿到对应值。键不存在,以默认值为值。如果不指定默认值且在右侧没有同名键属性名,则返回undenfined。除此之外还可以使用别名:

const { identifier: aliasIdentifier } = expression;

identifier是要访问的属性的名称,aliasIdentifier是变量的名称,expression应评估为对象。销毁后,变量aliasIdentifier包含属性值。

等效代码:

const aliasIdentifier = expression.identifier;

对于用动态属性名称来解构对象:这个动态还真不是大家以为的那个动态,由于最基本的限制【键必须和被解构对象中属性名相同才可以解构出来】,这里的动态是能够类似于传参,有选择的从某一个对象中提取部分属性并返回。

const hero = {
  name: 'Batman',
  realName: 'Bruce Wayne'
};

const prop = 'name';
const { [prop]: name } = hero;
name; // => 'Batman'

const { [prop]: name } = hero是一个对象分解,将变量赋给namevalue hero[prop],其中prop是一个保存属性名称的变量。下面是一个函数样例:

	<body>
		<button onclick="test1({name:'波波'},'name')"> 测试</button>
	</body>
	<script>
		function test1(obj,nameProp){
			const{[nameProp]:name}=obj;
			console.log(obj)//{name: '波波'}
			console.log(`hellow ${name}`) //hellow 波波
			return `hellow ${name}`;
		}
	</script>

参数的解构

参数解构主要应用于方法中,是指兼容性更强。

传统参数顺序不能够随意放,因为每一个位置都对应实际调用函数是传入的值。

function test(val1,val2){
    console.log(`第一个参数是${val1},第二个参数是${val2}`);
}
//实参和形参的顺序是一一对应的
test(1,2);
test(2,1);

多个参数记不住怎么办,这时候传递对象就可以了,对象的优势是,不用按照参数的顺序来传参,相对于参数列表传递对象属性更好记也没有强制的顺序,如果命名足够清晰在后期维护代码的时候甚至只要看属性名就可以马上理解过来。

function infomation (user) {
// user.name
}
infomation({ name: 'xiaoer', age: 18 })

参数列表被对象替换解决了参数列表顺序的问题,可是每次调用的时候都需要从对象中取值使得函数每次都要访问对象,带来了变量长度变长和很多无意义的赋值。再者如果调用者不小心多传递了参数,再不巧函数中遍历了对象这可能会产生BUG,可以利用解构赋值来解决:

function infomation ({ name, age, height }) {

console.log(name) // 药水哥

console.log(age) // 18

console.log(height) // 173cm

}

infomation ({name: ' 药水哥 ',age: ' 18 ', height: ' 173cm '})

这个时候参数并不是可选的,对于没有输入的参数选项,值默认为undefinted。

		function test2({name,height,age}){
			console.log(`${name},${height},${age}`)
		}
		test2({name:'波波'}) //波波,undefined,undefined

为了解决默认值问题:使得我们的实参跟形参关系更加松,甚至可以不输入参数

function infomation ({ name = 'anonymous', age = 0, height = 160 }) {

console.log(name) // 药水哥

console.log(age) // 0

console.log(height) // 160

}

infomation ({ name: ' 药水哥 '})

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]

函数参数重命名:

有时候需要对参数进行重命名,但是已经很多地方都使用了这个参数时。可以在函数执行最开始的时候进行重命名,但是这样显然不够 geek(主要是不够偷懒)依旧利用解构赋值来实现重命名:

function infomation ({ name:username = 'anonymous', age = 0, height = 160 } = {}) {

console.log(name) // undefined

console.log(age) // 0

console.log(height) // 160

console.log(username) // anonymous

}

infomation()

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐