2015-06-09 12 views
10

Come è possibile identificare a livello di codice proprietà getter e setter in ES5?Come distinguere tra un getter e un setter e una semplice proprietà in 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)); 

Stampe:

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

'({a: 1})! .__ lookupGetter __ ("a")' sarà falso poiché 'a' non è un getter. Se fosse la funzione si sarebbe trasformata in true, quindi il risultato finale è come hasOwnProperty(), ma per i getter ... – dandavis

risposta

7

Quando si è stringify ING, si perderanno tutti gli oggetti undefined e la funzione. Invece, è possibile verificare se l'oggetto descrittore di beni restituiti ha un non-undefined get o set proprietà e decidere come questo

  1. Se il descrittore di proprietà ha una proprietà value, si tratta di una proprietà data normale.

  2. Se il descrittore di proprietà ha proprietà get e set ed entrambi hanno funzioni come valori, è una proprietà di accesso.

  3. Se il descrittore di proprietà ha il valore di get come funzione, è una proprietà getter.

  4. In caso contrario, una proprietà di setter.


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

Dal value c'è, si tratta di una proprietà data normale.

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

Qui, value non c'è, ma get proprietà è una funzione. Quindi una proprietà getter.

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

Anche qui, value non c'è, ma set proprietà è una funzione. Quindi una proprietà setter.


A parte questo, se si ha una proprietà di accesso, come questo

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 

È possibile scrivere questo come una funzione, come questo

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

La mia ipotesi è che il setter dovrebbe almeno ricevere un parametro e il getter non dovrebbe usare alcun parametro.

Tuttavia, probabilmente non sarà sempre così. Per scoprire quanti i parametri di una funzione richiede è possibile utilizzare 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; 
} 

Esempio di utilizzo:

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

Si utilizza JSON.stringify, che è ciò che rende questo difficile da vedere.Getter e setter sono funzioni, che non possono essere serializzate come JSON, quindi non vengono visualizzate. Mi piacerebbe semplicemente fare questo:

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

Secondo Object.getOwnPropertyDescriptor() MDN

Un descrittore di proprietà è un record con alcuni dei seguenti attributi:

  • get
    Una funzione che funge da getter per la proprietà o indefinita se non esiste getter (solo descrittori di accesso).
  • set
    Una funzione che funge da setter per la proprietà o non definita se non è presente un setter (solo descrittori di accesso).

Di conseguenza, se si utilizza questo su una proprietà che è una GET o funzione impostata, allora avrebbe dovuto essere quelli definiti (al contrario di non definito). Questo può essere visto con

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

enter image description here

dal codice mostrato dove .get mostra la funzione bar() e .set mostra la funzione bam(value).

jsFiddle Demo

Un modo semplice per esaminare questo in una funzione di supporto potrebbe essere

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]";  
} 
Problemi correlati