JSの面接問題の中で深度コピーの実現の解説

3221 ワード

面接で次のような場面に遭遇したことがありますか?
Q:子供は、どのようにオブジェクトをコピーするかを知っていますか?
R:この時、機知に富んだあなたは思い付くかもしれません。

Object.assign({}, obj);
Q:相手を深くコピーするにはどうすればいいですか?
R:機転のきくあなた

JSON.parse(JSON.stringify(obj));
Q:strigifyを使うという方法にはどんな弊害がありますか?
  • の性能の問題、strigifyは更に解析して実は多くの時間を必要として、特にデータ量が大きい時。
  • のいくつかのタイプはコピーできません。例えば、関数(出力されない)、正則(出力されないオブジェクト)、時間オブジェクト(出力時間文字列)、Udefiend(出力されない)
  • 循環参照の対象に遭遇したらエラーが発生します。
  • 同層(同層ではない)が引用している問題で、理論的には2つのkeyに対応するvalが同一のオブジェクトを指すなら、コピーも同じ新しい住所を指すべきです。
    Q:深度コピー関数は自分で実現できますか?
    R:以下の通りです
    
    const deepClone = (obj) => {
     //              
     if (!obj || typeof obj !== 'object') return obj;
    
     //          
     switch(Object.prototype.toString.call(obj).slice(8, -1)) {
      case 'Date': 
       return new Date(obj);
       break;
      case 'RegExp': 
       return new RegExp(obj);
       break;
      case 'String': 
       return new String(obj);
       break;
      case 'Number': 
       return new Number(obj);
       break;
      case 'Boolean': 
       return new Boolean(obj);
       break;
     }
    
     const result = obj instanceof Array ? [] : {};
    
     for (let propName in obj) {
      if (obj.hasOwnProperty(propName)) {
       result[propName] = deepClone(obj[propName]);
      }
     }
    
     return result;
    }
    利点:ほとんどのデータタイプのコピーを実現し、すべての非引用タイプと引用タイプのString Number Boolean Function Aray Date RegExp
    短所:Error Math Symbol Map Set JSONのような特別な引用タイプは考慮されていません。関数は参照コピーであり、循環参照の問題は解決されていません。
    Q:循環参照はどうやって解決しますか?
    R:親レベルのデータキャッシュを比較する(同層(非同層)同引用の問題も解決できる)
    
    const deepClone = (obj) => {
     //              
     if (!obj || typeof obj !== 'object') return obj;
    
     //          
     switch (Object.prototype.toString.call(obj).slice(8, -1)) {
      case 'Date':
       return new Date(obj);
       break;
      case 'RegExp':
       return new RegExp(obj);
       break;
      case 'String':
       return new String(obj);
       break;
      case 'Number':
       return new Number(obj);
       break;
      case 'Boolean':
       return new Boolean(obj);
       break;
     }
    
     const map = deepClone.map = deepClone.map || new Map();
    
     //   map          ,    
     if (map.get(obj)) {
      return map.get(obj);
     }
    
     const result = obj instanceof Array ? [] : {};
    
     //                      
     map.set(obj, result);
    
     for (let propName in obj) {
      if (obj.hasOwnProperty(propName)) {
       result[propName] = deepClone(obj[propName]);
      }
     }
    
     return result;
    }
    Q:なぜ関数は元の関数を指していますか?新しい関数を作成しません。
    R:理論下の関数はnew Function(code)によって新しい関数を作成することもできますが、もしクローズド関数が発生したら、元の関数の外層定義の変数と元の作用領域チェーンを得ることができません。これらはJS語法の解析時に完成したステップは分かりません。すべては元の関数を参照した方がいいです。
    Sum:上記の欠点は主に特別な引用タイプを完全にカバーしていませんが、実は私達は普段これらのタイプに出会うはずがないので、間に合わせて使うことができます。他の問題があったら、考えられなかったり、間違えたりしたら、指摘してください。
    以上はJSの面接問題の中で深くコピーしたのが説明の詳しい内容を実現して、もっと多いJSの深くコピーする実現の資料に関して私達のその他の関連している文章に関心を持って下さい!