1. 程式人生 > 實用技巧 >單例設計模式及應用

單例設計模式及應用

技術標籤:javascript

關於深拷貝淺拷貝,原型,型別校驗,遞迴深拷貝

深拷貝和淺拷貝
如何區分深拷貝與淺拷貝,簡單點來說,就是假設B複製了A,當修改A時,看B是否會發生變化,如果B也跟著變了,說明這是淺拷貝,拿人手短,如果B沒變,那就是深拷貝,自食其力。

資料分為基本資料型別(String, Number, Boolean, Null, Undefined,Symbol)和物件資料型別。

引用資料型別的特點:儲存的是該物件在棧中引用,真實的資料存放在堆記憶體裡

引用資料型別在棧中儲存了指標,該指標指向堆中該實體的起始地址。當直譯器尋找引用值時,會首先檢索其在棧中的地址,取得地址後從堆中獲得實體。

比如淺拷貝:
在這裡插入圖片描述

當b=a進行拷貝時,其實複製的是a的引用地址,而並非堆裡面的值。
在這裡插入圖片描述

而當我們a[0]=1時進行陣列修改時,由於a與b指向的是同一個地址,所以自然b也受了影響,這就是所謂的淺拷貝了。

那,要是在堆記憶體中也開闢一個新的記憶體專門為b存放值,就像基本型別那樣,豈不就達到深拷貝的效果了

實現淺拷貝的方法

(1)for···in只迴圈第一層

// 只複製第一層的淺拷貝
function simpleCopy(obj1) {
   var obj2 = Array.isArray(obj1) ? [] : {};
   for (let i in obj1) {
   obj2[i] = obj1[i];
  }
   return obj2;
}
var obj1 = {
   a: 1,
   b: 2,
   c: {
         d: 3
      }
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 4
alert(obj2.c.d); // 4
(2)Object.assign方法
var obj = {
    a: 1,
    b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a) // 3

實現深拷貝的方法

(1)採用遞迴去拷貝所有層級屬性

function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判斷ojb子元素是否為物件,如果是,遞迴複製
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,簡單複製
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a=[1,2,3,4],
    b=deepClone(a);
a[0]=2;
console.log(a,b);
 (2) 通過JSON物件來實現深拷貝

function deepClone2(obj) {
  var _obj = JSON.stringify(obj),
    objClone = JSON.parse(_obj);
  return objClone;
}
缺點: 無法實現對物件中方法的深拷貝,會顯示為undefined
(7)如果物件的value是基本型別的話,也可以用Object.assign來實現深拷貝,但是要把它賦值給一個空物件
var obj = {
    a: 1,
    b: 2
}
var obj1 = Object.assign({}, obj); // obj賦值給一個空{}
obj1.a = 3;
console.log(obj.a);// 1

原型

一個可以被複制(或者叫克隆)的一個類,通過複製原型可以建立一個一模一樣的新物件,也可以說原型就是一個模板,在設計語言中更準確的說是一個物件模板
1)原型是定義了一些公用的屬性和方法,利用原型創建出來的新物件例項會共享原型的所有屬性和方法
例項程式碼:

    // 建立原型
    var Person = function(name){
        this.name = name;
    };

    // 原型的方法
   Person.prototype.sayHello = function(){
       console.log(this.name+",hello");
   };

   // 例項化建立新的原型物件,新的原型物件會共享原型的屬性和方法
   var person1 = new Person("zhangsan");
   var person2 = new Person("lisi");

   // zhangsan,hello
   person1.sayHello();
   // lisi,hello
   person2.sayHello();
    // 開啟嚴格模式,原型的屬性和方法還是會被原型例項所共享的
   "use strict";

    // 建立原型
    var Person = function(name){
        this.name = name;
    };

    // 原型的方法
   Person.prototype.sayHello = function(){
       console.log(this.name+",hello");
   };

   // 例項化建立新的原型物件,新的原型物件會共享原型的屬性和方法
   var person1 = new Person("zhangsan");
   var person2 = new Person("lisi");

   // zhangsan,hello
   person1.sayHello();
   // lisi,hello
   person2.sayHello();

常用的校驗型別方法

typeof 不能校驗 物件 陣列 null

  1. typefo 不能效驗 物件 陣列 null
  2. instanceof 誰是誰的例項
  3. Object.prototype.toString.call 不能判斷例項
  4. constructor 判斷當前是誰的建構函式

遞迴深拷貝

    let arr = [1, 2, 3, 4, 5, { name: 123 }]
    // let arr = {name:1234}
    Object.prototype.clone = function (data) {
        // console.log(typeof(data));
        // console.log(Object.prototype.toString.call(data));
        // console.log(data instanceof Array);
        // console.log(data.constuctor == Object);
        if (typeof (data) == 'object') {
            // 判斷data的資料型別來建立sum的型別
            let sum = data instanceof Array ? [] : {}
            // console.log(sum);
            for (var i in data) {
                // console.log(data[i]);
                sum[i] = typeof (data[i]) == 'object' ? clone(data[i]) : data[i]
            }
            return sum
        } else {
            return data
        }
    }

    let num = clone(arr)
    console.log(num);