code: function linkList(opt) {
      var mainData = opt.mainData;
      var datas = opt.datas;
  
      if (!datas) {
          datas = {main: mainData};
          opt.datasAttr = {main: 'data'};
      }
      opt.datas = opt.mainData = null;
  
      linkAll(mainData, datas, opt);
  
      // Porxy data original methods.
      each(datas, function (data) {
          each(mainData.TRANSFERABLE_METHODS, function (methodName) {
              data.wrapMethod(methodName, zrUtil.curry(transferInjection, opt));
          });
  
      });
  
      // Beyond transfer, additional features should be added to `cloneShallow`.
      mainData.wrapMethod('cloneShallow', zrUtil.curry(cloneShallowInjection, opt));
  
      // Only mainData trigger change, because struct.update may trigger
      // another changable methods, which may bring about dead lock.
      each(mainData.CHANGABLE_METHODS, function (methodName) {
          mainData.wrapMethod(methodName, zrUtil.curry(changeInjection, opt));
      });
  
      // Make sure datas contains mainData.
      zrUtil.assert(datas[mainData.dataType] === mainData);
  }
docs: Caution: In most case, either list or its shallow clones (see list.cloneShallow) is active in echarts process. So considering heap memory consumption, we do not clone tree or graph, but share them among list and its shallow clones. But in some rare case, we have to keep old list (like do animation in chart). So please take care that both the old list and the new list share the same tree/graph. 
  @param {Object} opt
  @param {module:echarts/data/List} opt.mainData
  @param {Object} [opt.struct] For example, instance of Graph or Tree.
  @param {string} [opt.structAttr] designation: list[structAttr] = struct;
  @param {Object} [opt.datas] {dataType: data},
  like: {node: nodeList, edge: edgeList}.
  Should contain mainData.
  @param {Object} [opt.datasAttr] {dataType: attr},
  designation: struct[datasAttr[dataType]] = list;