>웹 프론트엔드 >JS 튜토리얼 >ES6의 구조 분해 할당 분석(코드 예)

ES6의 구조 분해 할당 분석(코드 예)

不言
不言앞으로
2018-11-16 15:33:462163검색

이 기사의 내용은 ES6의 구조 분해 할당 분석에 관한 것입니다(코드 예제). 이는 특정 참조 가치가 있으므로 도움이 필요한 친구에게 도움이 되기를 바랍니다.

ES6에서는 배열과 객체에서 값을 추출하고 특정 패턴에 따라 변수에 값을 할당할 수 있는데, 이를 구조 분해라고 합니다.

구조 분해할 수 있는 사람

배열을 사용하여 배열을 분해할 수 있습니다. Set 구조의 경우 배열 분해 할당을 사용할 수도 있습니다.
구조 분해 할당의 규칙은 등호 오른쪽의 값이 객체나 배열이 아닌 한 먼저 객체로 변환한다는 것입니다.

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

실제로 특정 데이터 구조에 Iterator 인터페이스가 있으면 배열 형태의 구조 분해 할당을 사용할 수 있습니다.

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는 기본적으로 Iterator 인터페이스를 갖는 생성기 함수(생성기 함수 참조)입니다. 구조 분해 할당은 이 인터페이스에서 값을 차례로 가져옵니다.
위 명령문에서는 등호 오른쪽의 값이 객체로 변환된 후 Iterator 인터페이스를 가지지 않거나(처음 5개 표현식) Iterator 인터페이스 자체가 없기 때문에 오류를 보고합니다( 마지막 표현). ​
구조 분해 할당 표현식(= 이후 표현식)의 오른쪽이 null 또는 정의되지 않은 것으로 평가되면 오류가 발생합니다. null 또는 정의되지 않은 내용을 읽으려고 하면 "런타임" 오류가 발생하기 때문입니다.

디스트럭처링 누락 초기화 오류

디스트럭처링을 사용하여 var, let 또는 const로 변수를 선언하는 경우 초기화 프로그램(즉, 등호 오른쪽의 값)을 제공해야 합니다. 다음 코드는 초기화 프로그램 누락으로 인해 오류가 발생합니다.

//    语法错误!
var    {type,name};
//    语法错误!
let    {type,name};
//    语法错误!
const {type,name};

객체 구조 분해와 유사하게 배열 분해에 var , let , const 를 사용하는 경우 초기화 프로그램을 제공해야 합니다.

선언된 변수는 구조 분해 할당에 사용됩니다

Objects

// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

위 코드는 JavaScript 엔진이 {x}를 코드 블록으로 인식하여 구문 오류가 발생하기 때문에 오류를 보고합니다. 이 문제는 JavaScript가 이를 코드 블록으로 해석하지 못하도록 줄 시작 부분에 중괄호를 쓰지 않음으로써만 해결될 수 있습니다.

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

Arrays

대입 표현식에서 배열 분해를 사용할 수 있지만 객체 분해와 달리 표현식을 괄호로 묶을 필요는 없습니다. 예:

let    colors=["red","green","blue"    ],
let    firstColor    =    "black",
let    secondColor    =    "purple";
[firstColor,secondColor    ]    =    colors;
console.log(firstColor);//    "red"
console.log(secondColor);//    "green"

할당 표현식의 값 분해

대입 분해 표현식의 값은 표현식의 오른쪽( = 뒤)에 있는 값입니다. 이는 구조 분해 할당 표현식을 값이 예상되는 모든 곳에서 사용할 수 있음을 의미합니다. 예를 들어, 함수에 값 전달:

let    node={type:    "Identifier",name:    "foo"},
let type = "Literal",
let name = 5;
function    outputInfo(value)    {
    console.log(value    ===    node);    //    true
}

outputInfo({type,name}=node);

console.log(type);//    "Identifier"
console.log(name);//    "foo"

배열 분해 할당

배열 분해 할당 표현식 rvalue 오류

등호의 오른쪽이 배열이 아닌 경우(또는 엄밀히 말하면 순회 가능한 구조가 아닌 경우) Iterator 참조) 오류가 보고됩니다.
{}를 사용하여 왼쪽을 구조 해제하면 rvalue가 객체로 변환되며 null 및 undefine을 제외하고는 오류가 보고되지 않습니다.

// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

1차원 배열의 해체

let [a, b, c] = [1, 2, 3];

위 코드는 배열에서 값을 추출하고 해당 위치에 따라 변수에 할당할 수 있음을 나타냅니다.

중첩 배열의 구조 분해

let    [firstColor,[secondColor]] = ["red",["green","lightgreen"],"blue"];
console.log(firstColor);//    "red"
console.log(secondColor);//    "green"

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 [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4

let    [,firstColor,[secondColor]] = ["red","blue",["green","lightgreen"]];
firstColor//blue
secondColor//["green","lightgreen"]

구조 분해 실패

지정된 위치의 항목이 존재하지 않거나 해당 값이 정의되지 않은 경우 구조 분해가 실패하고 변수의 값이 정의되지 않은 것과 같습니다.

let [foo] = [];
let [bar, foo] = [1];

기본값

지정된 위치에서 항목의 구조 분해에 실패하면 이 기본값이 사용됩니다.
ES6은 위치에 값이 있는지 확인하기 위해 내부적으로 엄격한 동등 연산자(===)를 사용합니다. 따라서 기본값은 배열 구성원이 정의되지 않음과 엄격하게 동일한 경우에만 적용됩니다.
배열 멤버가 null인 경우 null은 정의되지 않음과 엄격히 동일하지 않기 때문에 기본값이 적용되지 않습니다.

let    colors = ["red"];
let    [firstColor,secondColor    = "green"]=colors
console.log(firstColor);//"red"
console.log(secondColor);//    "green"

let [foo = true] = [];
foo // true

기본값이 표현식인 경우 표현식은 느리게 평가됩니다. 즉, 사용될 때만 평가됩니다.

function f() {
  console.log('aaa');
}

let [x = f()] = [1];

위 코드에서는 x가 값을 얻을 수 있기 때문에 f 함수는 전혀 실행되지 않습니다. 위의 코드는 실제로 다음 코드와 동일합니다.
기본값은 구조 분해 할당의 다른 변수를 참조할 수 있지만 변수가 선언되어 있어야 합니다.

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

남은 항목 구조 분해

배열 분해에는 나머지 항목(                         항목)이라는 유사한 개념이 있으며, 구문을 사용하여 나머지 항목을 지정된 변수에 할당합니다.

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

하지만 또 다른 유용한 기능이 있습니다. 편리하게 배열을 복제하는 것은 JS에서 눈에 띄게 놓친 기능입니다. ES5에서 개발자는 배열을 복제하기 위해 concat() 메서드를 사용하는 간단한 방법을 사용하는 경우가 많습니다.

var    colors = ["red","green","blue"];
var    clonedColors = colors.concat();
console.log(clonedColors);//"[red,green,blue]"

ES6에서는 나머지 구문을 사용하여 동일한 효과를 얻을 수 있습니다. 다음과 같이 구현되었습니다:

let    colors = ["red","green","blue"];
let    [...clonedColors] = colors;
console.log(clonedColors);//"[red,green,blue]"

주의! 나머지 항목은 배열 분해 패턴의 마지막 부분이어야 하며 뒤에 쉼표가 올 수 없습니다. 그렇지 않으면 구문 오류입니다.

객체 해체 및 할당

解构不仅可以用于数组,还可以用于对象。对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。  
对象的解构赋值的解构和数组的差不多,只是[]换为了{},嵌套对象多了个:,还有对象不在乎属性的顺序,所以对象的不完全解构是不必要像数组那样的,想要哪个属性直接写属性名就行了,同时还多了个别名的设置。

//普通对象的解构
let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

//嵌套对象的解构
let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};
let { p: [x, { y }] } = obj;
//注意,这时p是模式,不是变量,因此不会被赋值。
//如果p也要作为变量赋值,可以写成下
//let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
//另一个例子 
const node = {
  loc: {
    start: {
      line: 1,
      column: 5
    }
  }
};
let { loc, loc: { start }, loc: { start: { line }} } = node;
line // 1
loc  // Object {start: Object}
start // Object {line: 1, column: 5}
//注意,最后一次对line属性的解构赋值之中,只有line是变量,loc和start都是模式,不是变量。

//默认值
var {x = 3} = {};
x // 3
var {x, y = 5} = {x: 1};
x // 1
y // 5
//默认值生效的条件是,对象的属性值严格等于undefined
var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null

//解构不成功,变量的值等于undefined。
let {foo} = {bar: 'baz'};
foo // undefined
// foo这时等于undefined,再取子属性就会报错
let {foo: {bar}} = {baz: 'baz'};

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

设置别名

ES6    有一个扩展语法,允许你在给本地变量赋值时使用一个不同的名称。

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'

字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

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

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

let {length : len} = 'hello';
len // 5

数值和布尔值的解构赋值

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

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

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

let {toString} = NaN;
toString === Number.prototype.toString//true

函数参数的解构赋值

函数的参数也可以使用解构赋值。

function add([x, y]){
  return x + y;
}

add([1, 2]); // 3

上面代码中,函数add的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成变量x和y。对于函数内部的代码来说,它们能感受到的参数就是x和y。  
函数参数的解构也可以使用默认值。

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]

上面代码中,函数move的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。如果解构失败,x和y等于默认值。当    JS    的函数接收大量可选参数时,一个常用模式是创建一个    options    对象,其中包含了附加的参数。

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]

js会先把实参传进形参的右值,代替左值,如果没传,默认用形参的右值。  
undefined就会触发函数参数的默认值。

[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]

用途

交换变量的值

let x = 1;
let y = 2;

[x, y] = [y, x];

取出从函数返回的值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

// 返回一个数组

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({z: 3, y: 2, x: 1});

提取 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]

函数参数的默认值

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};

指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || 'default foo';这样的语句。

遍历 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);
}
// first is hello
// second is world

如果只想获取键名,或者只想获取键值,可以写成下面这样。

// 获取键名
for (let [key] of map) {
  // ...
}

// 获取键值
for (let [,value] of map) {
  // ...
}

输入模块的指定方法

加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

const { SourceMapConsumer, SourceNode } = require("source-map");

위 내용은 ES6의 구조 분해 할당 분석(코드 예)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제