让我们用Java语言创建一个新对象,该对象具有一种将数据设置为所创建实例的方法。
我想知道,当添加数据时,该数据将在内存中存在两次还是newObj.data和数据仅指向内存中的同一地址?
let data = {text: 'a text'};
let newObj = Object.create({
setData(argData) {
this.data = argData;
}
});
// is data and newObj.data twice in memory now?
如果可能已经问过类似的问题,我事先表示歉意(这是在撰写本文时的编辑提示)。我是这样,我还没有找到他们。也许它们的表述不同,但是我不知道该如何以其他方式提出这个问题。
答案 0 :(得分:7)
我想知道,当添加数据时,该数据将在内存中存在两次还是newObj.data和数据仅指向内存中的同一地址?
后者。 //--------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: ObservableConcurrentDictionary.cs
//
//--------------------------------------------------------------------------
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Threading;
using System.Diagnostics;
namespace System.Collections.Concurrent
{
/// <summary>
/// Provides a thread-safe dictionary for use with data binding.
/// </summary>
/// <typeparam name="TKey">Specifies the type of the keys in this collection.</typeparam>
/// <typeparam name="TValue">Specifies the type of the values in this collection.</typeparam>
[DebuggerDisplay("Count={Count}")]
public class ObservableConcurrentDictionary<TKey, TValue> :
ICollection<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>,
INotifyCollectionChanged, INotifyPropertyChanged
{
private readonly SynchronizationContext _context;
private readonly ConcurrentDictionary<TKey, TValue> _dictionary;
/// <summary>
/// Initializes an instance of the ObservableConcurrentDictionary class.
/// </summary>
public ObservableConcurrentDictionary()
{
_context = AsyncOperationManager.SynchronizationContext;
_dictionary = new ConcurrentDictionary<TKey, TValue>();
}
/// <summary>Event raised when the collection changes.</summary>
public event NotifyCollectionChangedEventHandler CollectionChanged;
/// <summary>Event raised when a property on the collection changes.</summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary.
/// </summary>
private void NotifyObserversOfChange()
{
var collectionHandler = CollectionChanged;
var propertyHandler = PropertyChanged;
if (collectionHandler != null || propertyHandler != null)
{
_context.Send(s =>
{
collectionHandler?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
propertyHandler?.Invoke(this, new PropertyChangedEventArgs("Count"));
propertyHandler?.Invoke(this, new PropertyChangedEventArgs("Keys"));
propertyHandler?.Invoke(this, new PropertyChangedEventArgs("Values"));
}, null);
}
}
/// <summary>
/// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary.
/// </summary>
/// <param name="actionType">Add or Update action</param>
/// <param name="changedItem">The item involved with the change</param>
private void NotifyObserversOfChange(NotifyCollectionChangedAction actionType, object changedItem)
{
var collectionHandler = CollectionChanged;
var propertyHandler = PropertyChanged;
if (collectionHandler != null || propertyHandler != null)
{
_context.Send(s =>
{
collectionHandler?.Invoke(this, new NotifyCollectionChangedEventArgs(actionType, changedItem));
propertyHandler?.Invoke(this, new PropertyChangedEventArgs("Count"));
propertyHandler?.Invoke(this, new PropertyChangedEventArgs("Keys"));
propertyHandler?.Invoke(this, new PropertyChangedEventArgs("Values"));
}, null);
}
}
/// <summary>
/// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary.
/// </summary>
/// <param name="actionType">Remove action or optionally an Add action</param>
/// <param name="item">The item in question</param>
/// <param name="index">The position of the item in the collection</param>
private void NotifyObserversOfChange(NotifyCollectionChangedAction actionType, object item, int index)
{
var collectionHandler = CollectionChanged;
var propertyHandler = PropertyChanged;
if (collectionHandler != null || propertyHandler != null)
{
_context.Send(s =>
{
collectionHandler?.Invoke(this, new NotifyCollectionChangedEventArgs(actionType, item, index));
propertyHandler?.Invoke(this, new PropertyChangedEventArgs("Count"));
propertyHandler?.Invoke(this, new PropertyChangedEventArgs("Keys"));
propertyHandler?.Invoke(this, new PropertyChangedEventArgs("Values"));
}, null);
}
}
/// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary>
/// <param name="item">The item to be added.</param>
/// <returns>Whether the add was successful.</returns>
private bool TryAddWithNotification(KeyValuePair<TKey, TValue> item)
=> TryAddWithNotification(item.Key, item.Value);
/// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary>
/// <param name="key">The key of the item to be added.</param>
/// <param name="value">The value of the item to be added.</param>
/// <returns>Whether the add was successful.</returns>
private bool TryAddWithNotification(TKey key, TValue value)
{
bool result = _dictionary.TryAdd(key, value);
int index = IndexOf(key);
if (result) NotifyObserversOfChange(NotifyCollectionChangedAction.Add, value, index);
return result;
}
/// <summary>Attempts to remove an item from the dictionary, notifying observers of any changes.</summary>
/// <param name="key">The key of the item to be removed.</param>
/// <param name="value">The value of the item removed.</param>
/// <returns>Whether the removal was successful.</returns>
private bool TryRemoveWithNotification(TKey key, out TValue value)
{
int index = IndexOf(key);
bool result = _dictionary.TryRemove(key, out value);
if (result) NotifyObserversOfChange(NotifyCollectionChangedAction.Remove, value, index);
return result;
}
/// <summary>Attempts to add or update an item in the dictionary, notifying observers of any changes.</summary>
/// <param name="key">The key of the item to be updated.</param>
/// <param name="value">The new value to set for the item.</param>
/// <returns>Whether the update was successful.</returns>
private void UpdateWithNotification(TKey key, TValue value)
{
_dictionary[key] = value;
NotifyObserversOfChange(NotifyCollectionChangedAction.Replace, value);
}
/// <summary>
/// WPF requires that the reported index for Add/Remove events are correct/reliable. With a dictionary there
/// is no choice but to brute-force search through the key list. Ugly.
/// </summary>
private int IndexOf(TKey key)
{
var keys = _dictionary.Keys;
int index = -1;
foreach(TKey k in keys)
{
index++;
if (k.Equals(key)) return index;
}
return -1;
}
// ICollection<KeyValuePair<TKey,TValue>> Members
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
=> TryAddWithNotification(item);
void ICollection<KeyValuePair<TKey, TValue>>.Clear()
{
_dictionary.Clear();
NotifyObserversOfChange();
}
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
=> ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Contains(item);
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
=> ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex);
int ICollection<KeyValuePair<TKey, TValue>>.Count
{
get => _dictionary.Count;
}
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
{
get => ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).IsReadOnly;
}
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
=> TryRemoveWithNotification(item.Key, out TValue temp);
// IEnumerable<KeyValuePair<TKey,TValue>> Members
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
=> _dictionary.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> _dictionary.GetEnumerator();
// IDictionary<TKey,TValue> Members
public void Add(TKey key, TValue value)
=> TryAddWithNotification(key, value);
public bool ContainsKey(TKey key)
=> _dictionary.ContainsKey(key);
public ICollection<TKey> Keys
{
get { return _dictionary.Keys; }
}
public bool Remove(TKey key)
=> TryRemoveWithNotification(key, out TValue temp);
public bool TryGetValue(TKey key, out TValue value)
=> _dictionary.TryGetValue(key, out value);
public ICollection<TValue> Values
{
get => _dictionary.Values;
}
public TValue this[TKey key]
{
get => _dictionary[key];
set => UpdateWithNotification(key, value);
}
}
}
和newObj.data
中保存的是称为对象引用的东西,而不是对象本身。目的是在存储器(仅一次)别处;该引用是一个告诉JavaScript引擎对象所在位置的值。
这是假设您曾经实际致电data
。只是newObj.setData(data)
本身并没有在Object.create
上设置data
属性。
让我们扔一些ASCII艺术。完成此操作后:
newObj
...您的内存中有类似的内容(省略了许多详细信息):
+−−−−−−−−−−−−−−−−+ data:[Ref54611]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−>| (object) | +−−−−−−−−−−−−−−−−+ | [[Prototype]] |−−+ | text: 'a text' | | +−−−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−+ +−>(Object.prototype) newObj:[Ref74135]−−−>| (object) | | +−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+ | | [[Prototype]] |−−−>| (object) | | | text: 'a text' | +−−−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ | [[Prototype]] |−−+ | setData:[Ref55462] |−−−−>(function) +−−−−−−−−−−−−−−−−−−−−+
之后:
let data = {text: 'a text'};
let newObj = Object.create({
setData(argData) {
this.data = argData;
}
});
...你有类似的东西
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | \ +−−−−−−−−−−−−−−−−+ | data:[Ref54611]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−>| (object) | | +−−−−−−−−−−−−−−−−+ | | [[Prototype]] |−−+ | | text: 'a text' | | | +−−−−−−−−−−−−−−−−+ | | \ | +−−−−−−−−−−−−−−−−−−+ +−>(Object.prototype) | newObj:[Ref74135]−−−>| (object) | / | +−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+ | | | [[Prototype]] |−−−>| (object) | | | | text: 'a text' | +−−−−−−−−−−−−−−−−−−−−+ | | | data: [Ref54611] |−−+ | [[Prototype]] |−−+ | +−−−−−−−−−−−−−−−−−−+ | | setData:[Ref55462] |−−−−>(function) | | +−−−−−−−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
请注意,概念值“ [Ref54611]”同时位于newObj.setData(data);
(变量)和data
(属性)中。您实际上从未在代码中看到对象引用的值,但您可以将它们视为告诉引擎对象所在位置的数字。
答案 1 :(得分:0)
这是经典的参考与价值问题。 对于JS,情况总是后者,因为总是会引用对象。
您可以在此处找到示例: Javascript by reference vs. by value