title: Upsert
stage: 2.7
contributors: Jonas Haukenes, Daniel Minor
markEffects: true

Introduction

Given a `key` and a value, the `getOrInsert` method will return the existing value if it exists, or otherwise insert the provided default value and return that value.

Similarly, given a `key` and a callback function, the `getOrInsertComputed` method will return the existing value if it exists, or otherwise insert the returned value of the callback function, and return that value.

Map.prototype.getOrInsert ( _key_, _value_ )

When the getOrInsert method is called the following steps are taken:

1. Let _M_ be the *this* value. 1. Perform ? RequireInternalSlot(_M_, [[MapData]]). 1. Set _key_ to CanonicalizeKeyedCollectionKey(_key_). 1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[MapData]], do 1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, return _p_.[[Value]]. 1. Let _p_ be the Record { [[Key]]: _key_, [[Value]]: _value_ }. 1. Append _p_ to _M_.[[MapData]]. 1. Return _value_.

Map.prototype.getOrInsertComputed ( _key_, _callback_ )

When the getOrInsertComputed method is called the following steps are taken:

1. Let _M_ be the *this* value. 1. Perform ? RequireInternalSlot(_M_, [[MapData]]). 1. If IsCallable(_callback_) is *false*, throw a *TypeError* exception. 1. Set _key_ to CanonicalizeKeyedCollectionKey(_key_). 1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[MapData]], do 1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, return _p_.[[Value]]. 1. Let _value_ be ? Call(_callback_, *undefined*, « _key_ »). 1. NOTE: The Map may have been modified during execution of _callback_. 1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[MapData]], do 1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, then 1. Set _p_.[[Value]] to _value_. 1. Return _value_. 1. Let _p_ be the Record { [[Key]]: _key_, [[Value]]: _value_ }. 1. Append _p_ to _M_.[[MapData]]. 1. Return _value_.

WeakMap.prototype.getOrInsert ( _key_, _value_ )

When the getOrInsert method is called the following steps are taken:

1. Let _M_ be the *this* value. 1. Perform ? RequireInternalSlot(_M_, [[WeakMapData]]). 1. If CanBeHeldWeakly(_key_) is *false*, throw a *TypeError* exception. 1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[WeakMapData]], do 1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, return _p_.[[Value]]. 1. Let _p_ be the Record { [[Key]]: _key_, [[Value]]: _value_ }. 1. Append _p_ to _M_.[[WeakMapData]]. 1. Return _value_.

WeakMap.prototype.getOrInsertComputed ( _key_, _callback_ )

When the getOrInsertComputed method is called the following steps are taken:

1. Let _M_ be the *this* value. 1. Perform ? RequireInternalSlot(_M_, [[WeakMapData]]). 1. If CanBeHeldWeakly(_key_) is *false*, throw a *TypeError* exception. 1. If IsCallable(_callback_) is *false*, throw a *TypeError* exception. 1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[WeakMapData]], do 1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, return _p_.[[Value]]. 1. Let _value_ be ? Call(_callback_, *undefined*, « _key_ »). 1. NOTE: The WeakMap may have been modified during execution of _callback_. 1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[WeakMapData]], do 1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, then 1. Set _p_.[[Value]] to _value_. 1. Return _value_. 1. Let _p_ be the Record { [[Key]]: _key_, [[Value]]: _value_ }. 1. Append _p_ to _M_.[[WeakMapData]]. 1. Return _value_.