Codelet Keep code simple stupid

JavaScript解构赋值

解构赋值语法是ES6的新特性,我们可以借助解构赋值写出简短优雅的代码,多运用解构赋值可以很大的提高 代码的可读性,提高开发效率。现在很多转译工具(如Babel)会帮助我们处理解构赋值语句,自动兼容低版 本的JS引擎,所以我们需要读一读这些辅助代码,才能知道工具为我们做了什么。

解构赋值大致有如下的几种用法:

  1. 交换变量
let a = 0
let b = 1
let c = 2
[a, b, c] = [b, c, a]

会被转译为:

"use strict";

var a = 0;
var b = 1;
var c = 2;
var _ref = [b, c, a];
a = _ref[0];
b = _ref[1];
c = _ref[2];
_ref;
  1. 多返回值
function getResult () { return [] }

let [a, b, c] = getResult()

和变量解构一样,返回值会由一个中间变量存储,下面的_slicedToArray用于把可迭代对象转化成数组

function getResult() { return []; }

var _getResult = getResult(),
  _getResult2 = _slicedToArray(_getResult, 3),
  a = _getResult2[0],
  b = _getResult2[1],
  c = _getResult2[2];
  1. 参数解构
function putArray ([a, b, c]) {}

function putObject ({ x: a, y: b, z: c }) {}

函数传参实际上是隐式的变量赋值,因此也可以使用解构语法,除了数组以外对象也是可以解构的

function putArray(_ref) {
  var _ref2 = _slicedToArray(_ref, 3),
    a = _ref2[0],
    b = _ref2[1],
    c = _ref2[2];
}

function putObject(_ref3) {
  var a = _ref3.x,
    b = _ref3.y,
    c = _ref3.z;
}

再来看看_slicedToArray是怎么运作的,函数看似很长其实并不复杂,实际上就是利用for-of语句 遍历迭代器,和之前介绍的有很多重复之处

var _slicedToArray = function () {
  function sliceIterator(arr, i) {
    var _arr = []; // 结果数组
    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
      for (var _iterator = arr[Symbol.iterator](),
          _step;
          !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
          _iteratorNormalCompletion = true) { // for-of遍历
        _arr.push(_step.value);
        if (i && _arr.length === i) break; // 达到指定长度,若未指定则遍历至结束
      }
    } catch (err) {
      _didIteratorError = true;
      _iteratorError = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion && _iterator.return) {
          _iterator.return();
        }
      } finally {
        if (_didIteratorError) {
          throw _iteratorError;
        }
      }
    }

    return _arr;
  }

  return function (arr, i) {
    if (Array.isArray(arr)) {
      return arr;
    } else if (Symbol.iterator in Object(arr)) {
      return sliceIterator(arr, i); // 若是可迭代对象则只截取前i个
    } else {
      throw new TypeError("Invalid attempt to destructure non-iterable instance");
    }
  };
}();
  1. 默认属性值
let obj = {
  a: 1
}

let {
  a = 0,
  b = 0
} = obj

解构的同时还可以指定默认参数,对函数传参也一样适用

"use strict";

var obj = {
  a: 1
};

var _obj$a = obj.a,
    a = _obj$a === undefined ? 0 : _obj$a,
    _obj$b = obj.b,
    b = _obj$b === undefined ? 0 : _obj$b;
  1. 深对象赋值
var obj = {
  a: 0,
  b: {
    c: 1,
    d: {
      e: 2
    }
  }
}

var {
  a,
  b: {
    d: {
      e: e
    }
  }
} = obj

解构赋值还可以用于获取深对象中的属性值,不过为了更安全的操作最好还是用_.get()

"use strict";

var obj = {
  a: 0,
  b: {
    c: 1,
    d: {
      e: 2
    }
  }
};

var a = obj.a,
    e = obj.b.d.e;