Как различать геттер и сеттер и простое свойство в JavaScript?

Как я могу программно идентифицировать свойства getter и setter в ES5?

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));

Печать

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

Ответ 1

Когда вы stringify ing, вы потеряете все объекты undefined и Function. Вместо этого вы можете проверить, имеет ли объект дескриптора возвращаемого свойства свойства не undefined get или set и решает, как это сделать

  • Если дескриптор свойства имеет свойство value, это нормальное свойство данных.

  • Если дескриптор свойства имеет свойства get и set, и обе функции имеют значения как значения, то это свойство accessor.

  • Если дескриптор свойства имеет get значение как функцию, то это свойство getter.

  • В противном случае свойство setter.


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

Так как value есть, это нормальное свойство данных.

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

Здесь value не существует, но свойство get является функцией. Таким образом, свойство getter.

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

Здесь также value не существует, но свойство set является функцией. Таким образом, свойство setter.


Кроме того, если у вас есть свойство accessor, вроде этого

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

Вы можете написать это как функцию, например

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

Ответ 2

Вы используете JSON.stringify, что делает это трудным для просмотра. Getter и seters - это функции, которые не могут быть сериализованы как JSON, поэтому они не отображаются. Я просто сделал бы это:

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.
}

Ответ 3

jsFiddle Demo

В соответствии с Object.getOwnPropertyDescriptor() MDN

Дескриптор свойства - это запись с некоторыми из следующих атрибутов:

  • прибудет
    Функция, которая служит в качестве getter для свойства, или undefined, если нет геттера (только дескрипторы доступа).
  • установить
    Функция, которая служит средством настройки для свойства, или undefined, если нет setter (только дескрипторы доступа).

В результате, если вы используете это для свойства, которое является функцией get или set, тогда оно должно быть определено (в отличие от undefined). Это можно увидеть с помощью

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

enter image description here

Из вашего показанного кода, где .get показывает функцию bar() и .set, показывает функцию bam(value).

jsFiddle Demo

Простым способом изучения этого в вспомогательной функции может быть

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

Ответ 4

Я предполагаю, что установщик должен хотя бы получить один параметр, и геттер не должен использовать какой-либо параметр.

Однако, вероятно, это не всегда так. Чтобы узнать, сколько параметров требуется для функции, вы можете использовать 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;
}

Пример использования:

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 []