2015-06-09 14 views
10

Jak mogę programowo zidentyfikować właściwości gettera i ustawiającego w ES5?Jak odróżnić getter od settera od zwykłej właściwości w JavaScript?

var o, descriptor, descriptorGetter, descriptorSetter; 

o = { 
    foo: 'foo', 
    get bar() { 
    return 'bar'; 
    }, 
    set bam(value) { 
    this._bam = value; 
    }, 
}; 

descriptor = Object.getOwnPropertyDescriptor(o, 'foo'); 
descriptorGetter = Object.getOwnPropertyDescriptor(o, 'bar'); 
descriptorSetter = Object.getOwnPropertyDescriptor(o, 'bam'); 

console.log(JSON.stringify(descriptor)); 
console.log(JSON.stringify(descriptorGetter)); 
console.log(JSON.stringify(descriptorSetter)); 

Wydruki:

{"value":"foo","writable":true,"enumerable":true,"configurable":true} 
{"enumerable":true,"configurable":true} 
{"enumerable":true,"configurable":true} 
+0

'({a: 1})! .__ lookupGetter __ ("a")' będzie false, ponieważ 'a' nie jest getter. Gdyby była to funkcja, która wymusiłaby na true, tak wynik końcowy jest jak hasOwnProperty(), ale dla pobierających ... – dandavis

Odpowiedz

7

Kiedy jesteś stringify ing, stracisz wszystkie obiekty undefined i funkcję. Zamiast tego, można sprawdzić, czy zwrócony obiekt deskryptor obiekcie non-undefined get lub set właściwości i zdecydować, jak to

  1. Jeśli deskryptor nieruchomość ma właściwość value, jest to normalna właściwość danych.

  2. Jeśli deskryptor właściwości ma właściwości get i set, a obie mają funkcje jako wartości, wówczas jest to właściwość akcesor.

  3. Jeśli deskryptor właściwości ma wartość get jako funkcję, wówczas jest to właściwość getter.

  4. W przeciwnym razie właściwość ustawiająca.


descriptor.hasOwnProperty('value'); 
// true 

Od value jest tam, jest to normalna właściwość danych.

descriptorGetter.hasOwnProperty('value'); 
// false 
typeof descriptorGetter.get === 'function'; 
// true 
typeof descriptorGetter.set === 'function'; 
// false 

Tutaj value tam nie ma, ale get nieruchomość jest funkcją. Więc właściwość gettera.

descriptorSetter.hasOwnProperty('value'); 
// false 
typeof descriptorSetter.get === 'function'; 
// false 
typeof descriptorSetter.set === 'function'; 
// true 

Tutaj również, value tam nie ma, ale set nieruchomość jest funkcją. Tak więc właściwość setera.


Poza tym, jeśli miał właściwość dostępowej, jak to

var o = { 
    get cabbage() { 
     return 'cabbage'; 
    }, 
    set cabbage(value) { 
     this._cabbage = value; 
    }, 
}; 

descriptorCabbage = Object.getOwnPropertyDescriptor(o, 'cabbage'); 

console.log(descriptorCabbage.hasOwnProperty('value')); 
// false 
console.log(typeof descriptorCabbage.get === 'function'); 
// true 
console.log(typeof descriptorCabbage.set === 'function'); 
// true 

Możesz napisać to w zależności, jak to

function getTypeOfProperty(object, property) { 
    var desc = Object.getOwnPropertyDescriptor(object, property); 

    if (desc.hasOwnProperty('value')) { 
     return 'data'; 
    } 

    if (typeof desc.get === 'function' && typeof desc.set === 'function') { 
     return 'accessor'; 
    } 

    return typeof desc.get === 'function' ? 'getter' : 'setter'; 
} 

console.log(getTypeOfProperty(o, 'foo')); 
// data 
console.log(getTypeOfProperty(o, 'bar')); 
// getter 
console.log(getTypeOfProperty(o, 'bam')); 
// setter 
console.log(getTypeOfProperty(o, 'cabbage')); 
// accessor 
0

Domyślam się że seter powinien przynajmniej otrzymać jeden parametr i getter nie powinien używać żadnego parametru.

Jednak prawdopodobnie nie zawsze tak będzie. Aby dowiedzieć się, ile parametrów funkcja wymaga, można użyć this

var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; 
var ARGUMENT_NAMES = /([^\s,]+)/g; 
function getParamNames(func) { 
    var fnStr = func.toString().replace(STRIP_COMMENTS, ''); 
    var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES); 
    if(result === null) 
    result = []; 
    return result; 
} 

Przykład użycia:

getParamNames(getParamNames) // returns ['func'] 
getParamNames(function (a,b,c,d){}) // returns ['a','b','c','d'] 
getParamNames(function (a,/*b,c,*/d){}) // returns ['a','d'] 
getParamNames(function(){}) // returns [] 
1

Używasz JSON.stringify, która jest co sprawia, że ​​to trudne do zauważenia.Getter i setery są funkcjami, których nie można serializować jako JSON, więc nie pojawiają się. ja po prostu to zrobić:

if ('value' in descriptor){ 
    // The descriptor is for a data property. 
    // Read 'descriptor.value' in here. 
} else { 
    // The descriptor is for an accessor property. 
    // Read 'descriptor.get' and 'descriptor.set' in here. 
} 
1

jsFiddle Demo

Według Object.getOwnPropertyDescriptor() MDN

Deskryptor nieruchomość jest zapisem niektóre z następujących cech:

  • get Funkcja, która służy jako getter dla właściwości, lub nieokreślona, ​​jeśli nie ma gettera (tylko deskryptory akcesorów).
  • zestaw
    Funkcja, która służy do ustawiania właściwości lub nieokreślona, ​​jeśli nie ma ustawnika (tylko deskryptory akcesorów).

W rezultacie, jeśli to wykorzystać na nieruchomości, która jest pobranie lub ustawienie funkcji to powinno ci być zdefiniowany (w przeciwieństwie do niezdefiniowany). Widać to z

console.log(descriptorGetter.get);//function bar() 
console.log(descriptorSetter.set);//function bam(value) 

enter image description here

ze swojego przedstawionym kodzie gdzie .get pokazuje funkcję bar() i .set pokazuje funkcję bam(value).

jsFiddle Demo

Prostym sposobem na zbadanie tego w funkcji pomocnika może być

function isGet(obj,prop){ 
return toString.call(Object.getOwnPropertyDescriptor(obj, prop).get) == "[object Function]";  
} 
function isSet(obj,prop){ 
return toString.call(Object.getOwnPropertyDescriptor(obj, prop).set) == "[object Function]";  
} 
Powiązane problemy