2013-07-05 24 views
1

我有一個默認值的構造函數:如何確定對象屬性是否已直接分配或繼承?

var myObject = function(){ 
    this.myValue = "default"; 
} 

我然後實例化一個新的對象:

var newInstance = new myObject(); 

我如何判斷myValue是原來的默認值,且尚未重新分配。我無法檢查價值,因爲它可能會被設置爲相同的,並且會產生誤報。

回答

5

使用Object.hasOwnProperty()

if (newInstance.hasOwnProperty('myValue')) { 
    // original default value 
} 

但是,這不能告訴你這是否發生了:

newInstance.myValue = 'default'; 

要檢測的是,你需要使用像getters/setters和跟蹤私人突變標誌:

function myObject() { 
    var _myValue = "default"; 
    var _wasMutated = false; 

    return { 
     get myValue() { 
      return _myValue; 
     }, 
     set myValue(x) { 
      _myValue = x; 
      _wasMutated = true; 
     }, 
     get wasMutated() { 
      return _wasMutated; 
     } 
    } 
} 

// usage: 
var newInstance = new myObject(); 
newInstance.myValue;    // "default" 
newInstance.wasMutated;    // false 
newInstance.myValue = "default"; 
newInstance.wasMutated;    // true 
newInstance.wasMutated = false;  // writes have no effect since there's no setter 
newInstance.wasMutated;    // true 
+0

我不認爲這是OP正在尋找的......他們想知道*值*是否已經改變; 'hasOwnProperty'不會告訴你這一點。 –

+0

我不知道。我想知道它是否直接設置。不是它是否必然改變 –

+0

啊,那麼@Matt Ball是正確的;你需要getters/setters。 –

1

有來完成你要找的內容沒有內置的方式,但它是很容易做的一個「默認值「對象:

var MyObject = function() { 
    this.myValue = this.defaults.myValue 
} 
MyObject.prototype.defaults = { myValue: 'default' }; 
MyObject.prototype.isDefault = function(prop) { 
    return this[prop]===this.defaults[prop]; 
} 

var o = new MyObject(); 
o.isDefault('myValue'); // returns true 
o.myValue = 'foo'; 
o.isDefault('myValue'); // returns false 
o.myValue = 'default'; 
o.isDefault('myValue'); // returns true 

在另一方面,如果你需要知道什麼是與否的屬性曾經被設置(不管它的價值),你將不得不使用私有屬性和getter/setter方法功能:

var MyObject = function() { 
    var myValue = 'default';  // i'm private! 
    var myValueHasChanged = false; 
    this.myValue = function(newVal) { 
     if(arguments.length===0) { 
      return newVal; 
     } else { 
      myValue = newVal; 
      myValueHasChanged = true; 
     } 
    } 
    this.myValueHasChanged = function() { 
     return myValueHasChanged; 
    } 
} 

var o = new MyObject(); 
o.myValue();    // returns 'default' 
o.myValueHasChanged(); // returns false 
o.myValue('foo'); 
o.myValue();    // returns 'foo' 
o.myValueHasChanged(); // returns true 
o.myValue('default'); 
o.myValueHasChanged(); // returns true 
+0

+1。我可以建議'if(arguments.length === 0)'而不是'if(newVal === undefined)',以便可以將值設置爲'undefined'? – nnnnnn

+0

這是一個很好的建議,@nnnnnn。我通常會避免*永遠*使用'undefined'作爲理所當然的事情(我認爲使用'undefined'保留給JS本身),但是你的建議確實會消除這個邊界情況,所以我會改變它。 –

2

我無法檢查的價值,因爲它可以被設置爲相同的,而且會產生假陽性。

如果你改變你的構造函數設定值,而是把它放在原型:

var myObject = function(){}; 
myObject.prototype.myValue = "default"; 

...那麼你可以使用.hasOwnProperty() method測試myValue是否已經即使它被設置爲與默認值相同的值,也會覆蓋

if (!newInstance.hasOwnProperty("myValue")) { 
    // has not been assigned another value 
} 

這工作,因爲如果你以後說:

newInstance.myValue = "something"; 

...這將在實例上直接創建myValue屬性。當您使用newInstance .myValue時,它會自動檢索直接屬性(如果存在)或否則將繼承原型屬性。

var newInstance = new myObject(); 

console.log(newInstance.myValue);     // "default" 
console.log(newInstance.hasOwnProperty("myValue")); // false 

newInstance.myValue = "default"; 
console.log(newInstance.myValue);     // "default" 
console.log(newInstance.hasOwnProperty("myValue")); // true 
+1

這是一個有趣的方法(upvote!),但是與往常一樣,在原型上定義事物時,必須記住該屬性然後在所有實例之間共享(除非,正如您指出的那樣,它被覆蓋)。如果這可能讓你陷入困境,你的財產本身就是一個對象。考慮一下,然後'myObject.myValue.prop ='foo';'。現在所有未覆蓋'myValue'的'MyObject'實例都發生了變化,而且這種氣味就像一種副作用。 –

+1

@EthanBrown - 你對屬性是完全正確的。對於那些當然你的方法或馬特的將覆蓋它。我承認我甚至沒有考慮過,因爲我只是想像OP的示例代碼中的字符串,但我認爲這對於那些原始值事例來說是合理的方法,因爲它使事情變得非常簡單。對於OP:謹慎使用。 – nnnnnn

+0

更確切地說,它將使用任何不可變的值,因爲您只能通過爲它們分配新值來更改它們。因此,如果它們是不可變的(如String ojbect),它就可以處理對象。由於您可以使用.splice,.sort .push ...來更改它,因此無法與Array一起使用。 – HMR