如何在JavaScript中区分getter、setter和普通属性?

14

我该如何以编程方式识别 ES5 中的 getter 和 setter 属性?

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}

!({a:1}).__lookupGetter__("a") 会返回 false,因为 a 不是 getter。如果它是 getter,那么函数将强制转换为 true,所以最终结果类似于 hasOwnProperty(),但是针对 getter... - dandavis
4个回答

10
当你使用`stringify`方法进行序列化时,所有的`undefined`和函数对象都将丢失。相反,你可以检查返回的属性描述符对象是否具有非undefined的`get`或`set`属性,并像这样做出决定:
1. 如果属性描述符具有`value`属性,则它是普通数据属性。 2. 如果属性描述符具有`get`和`set`属性,并且两者都具有函数值,则它是访问器属性。 3. 如果属性描述符具有`get`的值为函数,则它是getter属性。 4. 否则,是setter属性。
因为有`value`属性,所以它是一个普通数据属性。
descriptor.hasOwnProperty('value');
// true

这里,“value”不存在,但“get”属性是一个函数。所以它是一个getter属性:

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

同样,在这里,value 不存在,但 set 属性是一个函数。因此,set 属性是一个 setter 函数:

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

此外,如果您有一个访问器属性,像这样

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

1
您正在使用JSON.stringify,这就是为什么很难看到它的原因。Getter和setter是函数,无法作为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.
}

1

jsFiddle演示

根据Object.getOwnPropertyDescriptor() MDN

属性描述符是一个记录,具有以下一些属性:

  • get
    用作属性getter的函数,如果没有getter(仅访问器描述符),则为undefined。
  • set
    用作属性setter的函数,如果没有setter(仅访问器描述符),则为undefined。

因此,如果您在属性上使用它,该属性是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)。 < p > jsFiddle演示

检查这个辅助函数的简单方法可能是:
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]";    
}

0

我猜设置器至少应该接收一个参数,而获取器不应使用任何参数。

但是可能并非总是如此。要找出函数需要多少个参数,可以使用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 []

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接