2017-04-21 27 views
2

背景(爲什麼Object.update()jQuery.extend()是不是一個解決方案,以及爲什麼這不是其他的how-to-複製一個JavaScript的對象問題,一式兩份): 這個版本的拷貝,使用一個for循環如何在保留獲取者/設置者的情況下淺拷貝Javascript對象?

function copy_obj(obj) { 
    var copy = {}; 
    for (var attr in obj) if (obj.hasOwnProperty(attr)) { 
     copy[attr] = obj[attr]; 
    } 
    return copy; 
} 

只複製屬性的值(一樣Object.update())和失敗的物體上,如:

var myobj = { 
    _fname: 'fname', 
    _lname: 'lname', 
    get fullname() { return this._fname + ' ' + this._lname; }, 
    set fullname(v) { this._fname = v; } 
}; 

myobj.fullname === 'fname lname' // true 
myobj.fullname = 'Anton' 
myobj.fullname === 'Anton lname' // true 

var mycopy = copy_obj(myobj); 
mycopy.fullname === 'fname lname' // true 
mycopy.fullname = 'Anton' 
mycopy.fullname === 'Anton' // oops! 

問:我已經想通了,我需要使用getOwnPropertyNames /描述獲取/設置的描述,但我還沒有找到任何簡單的方法來確定,如果事情僅僅是一個普通的可以直接複製值 - 什麼進入if語句:

function copy_obj2(obj) { 
    var mycopy = {}; 
    Object.getOwnPropertyNames(obj).forEach(function (prop) { 
     var descriptor = Object.getOwnPropertyDescriptor(obj, prop); 
     if (/* descriptor is a plain value */) { 
      mycopy[prop] = obj[prop]; 
     } else { 
      Object.defineProperty(mycopy, prop, descriptor); 
     } 
    }); 
    return mycopy; 
} 

(我只是在複製類似對象的值,而不關心陣列或其他基本類型)。

+1

你爲什麼會在乎它是什麼類型的描述符? 'Object.defineProperty'也可以用來創建數據屬性。 – Bergi

+0

提示:「簡單」描述符具有'可寫'和'值'字段,不含'get'或'set'字段。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors#Description – Bergi

+0

不是一個數據描述符/屬性比普通的價值更多的開銷? – thebjorn

回答

2

您不需要擔心描述符的類型;無論是數據類型描述符還是訪問類型描述符,都可以直接使用它來在目標對象上創建屬性。

function copy_obj2(obj) { 
    var mycopy = {}; 
    Object.getOwnPropertyNames(obj).forEach(function (prop) { 
     var descriptor = Object.getOwnPropertyDescriptor(obj, prop); 
     Object.defineProperty(mycopy, prop, descriptor); 
    }); 
    return mycopy; 
} 

但你也可以使用getOwnPropertyDescriptors,用defineProperties

function copy_obj2(obj) { 
    return Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj)); 
} 

如果你也想在克隆原型,然後:

function copy_obj2(obj) { 
    return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); 
} 

然而,getOwnPropertyDescriptors不在IE中可用。建議填充here

+0

'getOwnPropertyDescriptors'在Chrome/FF上也是最近的,所以我可能不會在沒有添加polyfill的情況下使用它。 – thebjorn