如何从 JXA 中的对象获取多个属性?

How to get multiple properties from objects in JXA?

JXA 中有没有一种方法可以通过一次调用从多个对象中获取多个属性?

例如,我想从菜单项中获取 nameenabled 属性,可以对每个人 属性 进行如下操作:

Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.name()
Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.enabled()

但是是否可以通过单个函数调用来获取它们?类似于:

Application("System Events").processes.byName('Finder').menuBars[0].menuBarItems.select('name', 'enabled')

我知道,我可以遍历 menuBarItems 并从 .properties() 方法收集属性,但这种方法太慢了,这就是我寻找其他选择的原因。

更新

我正在寻找更好的性能,而不是更好的语法,即我希望在对 System Events.[=17= 的一次调用中检索属性]

我可能会这样做:

sys = Application('com.apple.systemevents');
FinderProc = sys.processes['Finder'];
FinderMenuBarItems = FinderProc.menuBars[0].menuBarItems();


Array.from(FinderMenuBarItems,x=>[x.name(),x.enabled()]);

通过首先将 object 转换为 array,这允许 map 每个元素并一次检索所有元素所需的属性。为了便于阅读,代码分为几行。

编辑: 添加于 2019-07-27

根据您关于 Objective-C 实施的评论,我今天有一点时间来编写一个 JSObjc 脚本。它与上面的普通 JXA 版本做同样的事情,而且,是的,它显然进行了多个函数调用,这是必要的。但它执行这些功能的级别低于 System Events(此处根本不涉及),因此希望您会发现它的性能更高。

ObjC.import('ApplicationServices');
ObjC.import('CoreFoundation');
ObjC.import('Foundation');
ObjC.import('AppKit');

var err = {
    '-25211':'APIDisabled',
    '-25206':'ActionUnsupported',
    '-25205':'AttributeUnsupported',
    '-25204':'CannotComplete',
    '-25200':'Failure',
    '-25201':'IllegalArgument',
    '-25202':'InvalidUIElement',
    '-25203':'InvalidUIElementObserver',
    '-25212':'NoValue',
    '-25214':'NotEnoughPrecision',
    '-25208':'NotImplemented',
    '-25209':'NotificationAlreadyRegistered',
    '-25210':'NotificationNotRegistered',
    '-25207':'NotificationUnsupported',
    '-25213':'ParameterizedAttributeUnsupported',
         '0':'Success' 
};

var unwrap = ObjC.deepUnwrap.bind(ObjC);
var bind = ObjC.bindFunction.bind(ObjC);

bind('CFMakeCollectable', [ 'id', [ 'void *' ] ]);
Ref.prototype.nsObject = function() {
    return unwrap($.CFMakeCollectable(this[0]));
}

function getAttrValue(AXUIElement, AXAttrName) {
    var e;
    var _AXAttrValue = Ref();

    e = $.AXUIElementCopyAttributeValue(AXUIElement,
                                        AXAttrName,
                                        _AXAttrValue);
    if (err[e]!='Success') return err[e];

    return _AXAttrValue.nsObject();
}

function getAttrValues(AXUIElement, AXAttrNames){
    var e;
    var _AXAttrValues = Ref();

    e = $.AXUIElementCopyMultipleAttributeValues(AXUIElement,
                                                 AXAttrNames,
                                                 0,
                                                 _AXAttrValues);
    if (err[e]!='Success') return err[e];

    return _AXAttrValues.nsObject();
}

function getAttrNames(AXUIElement) {
    var e;
    var _AXAttrNames = Ref();

    e = $.AXUIElementCopyAttributeNames(AXUIElement, _AXAttrNames);
    if (err[e]!='Success') return err[e];

    return _AXAttrNames.nsObject();
}


(() => {
    const pid_1        = $.NSWorkspace.sharedWorkspace
                                      .frontmostApplication
                                      .processIdentifier;   
    const appElement   = $.AXUIElementCreateApplication(pid_1);
    const menuBar      = getAttrValue(appElement,"AXMenuBar");
    const menuBarItems = getAttrValue(menuBar, "AXChildren");

    return menuBarItems.map(x => {
        return getAttrValues(x, ["AXTitle", "AXEnabled"]);
    });
})();