5

使用脚本编辑器使用新的 JS 进行自动化。我在以下最后一行遇到错误:

var iTunes = Application("iTunes");
var sources = iTunes.sources();
var library = sources.whose({name : "Library"});

确认源数组符合预期(两个元素,一个带有name“库”,一个带有“Internet Radio”)。但最后一行令人窒息Error on line 3: TypeError: undefined is not a function (evaluating 'sources.whose({name : "Library"})')

据我所知,我为函数使用了正确的语法whose。(我也尝试使用明确的_equals子句来获得相同的结果。)我做错了什么?

4

4 回答 4

8

我究竟做错了什么?

简短的回答:这不是你的错。JXA 文档是一袋谎言。

更长的解释:对象的元素与数组无关。它们表示对象图中的一对多关系,在这种情况下,是一个source对象与零个或多个library对象之间的关系。

虽然许多关系可能反映底层实现的包含层次结构,但没有义务这样做;例如,Finder 允许您以多种方式识别桌面上的对象:

items of folder "Desktop" of folder "jsmith" of folder "Users" of disk "Macintosh HD" of app "Finder"
items of folder "Desktop" of folder "jsmith" of folder "Users" of startup disk of app "Finder"
items of folder "Desktop" of home of app "Finder"
items of folder "Macintosh HD:Users:jsmith:Desktop" of app "Finder"
items of desktop of app "Finder"
items of app "Finder"
[etc.]

Apple 基于事件的应用程序脚本基于远程过程调用和简单的一流查询。它不是OOP,不管表面如何:这只是语法糖,使它的查询易于阅读和编写。

...

在这种情况下,您的第二行是告诉 iTunes 获取一个查询对象 (ObjectSpecifiers) 的列表 (Array),用于标识sourceiTunes 应用程序中的每个对象:

var iTunes = Application("iTunes");
var sources = iTunes.sources();

一旦你有了一个数组,你就不能用它来构建进一步的查询,因为 JavaScript 本身不知道如何构建查询。你真正想要的是这样的:

var iTunes = Application("iTunes");
var sourcesSpecifier = iTunes.sources;
var librarySpecifier = sourcesSpecifier.whose({name : "Library"});

这将为您提供一个对象说明符,用于标识source名称为“库”的所有对象。(如果您只想指定名为“Library”的第一个 对象,请使用该方法而不是; 它更简单。)sourcebyNamewhose

--

就个人而言,我认为所有这些都有些学术性,因为 JXA 的 Apple 事件桥实现,就像它的文档一样,主要是由 Lame 和 Fail 组成的。它主要在一定程度上起作用,然后在你身上大便。如果您的需求是适度的,并且它“足够好”可以为您提供更多功能,但对于任何不平凡的 AppleScript 坚持:它是唯一有效的受支持解决方案。

(AppleScript/JXA 团队也没有为这种垃圾工作找借口:几个月前我给他们发了一个几乎完成的 JavaScriptOSA 参考实现,让他们按照他们的意愿学习或窃取,他们完全忽略了。所以你会原谅我的小便,因为这是很久以前解决的问题。)

于 2014-11-23T19:12:28.220 回答
2

现在,这正如理论所预测的那样有效。

(function () {
    'use strict';

    var iTunes = Application('iTunes'),
        filtered = iTunes.sources.whose({
            name: 'Library'
        });

    return filtered().length;

})();
于 2016-02-13T13:53:53.637 回答
0

基于JavaScript for Automation 发行说明 Mail.inbox.messages.whose(...)示例,以下内容应该有效:

var iTunes = Application('iTunes');
var filtered = iTunes.sources.whose({name : 'Library'});

具有“包含查询的对象”的“特殊whose方法”的明显目标是通过仅将 OS X 对象层次结构中的选择项(或项引用)引入结果 JavaScript 数组来提高效率。

但是,... whoseJXA 的功能在早期的 OS X v10.10 版本中似乎存在一些错误。

因此,由于所讨论的数组很小(即 2 项),在将元素作为 JS 数组后,可以在 JavaScript 端快速可靠地进行过滤。

解决方法示例 1

var iTunes = Application('iTunes');
var sources = iTunes.sources();
var librarySource = null;
for (key in sources) {
    var name = sources[key].name();
    if (name.localeCompare("Library") == 0) {
        librarySource = sources[key];
    }
}

解决方法示例 2

var iTunes = Application('iTunes');
var sources = iTunes.sources();
function hasLibraryName(obj) {
    var name = obj.name();
    if (name.localeCompare("Library") == 0) {
        return true;
    }
    return false;
}
var filtered = sources.filter(hasLibraryName); 
于 2015-05-01T10:14:57.537 回答
0

在 OS X 10.11.5 中,这似乎工作得很好。

library = Application("iTunes").sources.whose({name:'Library'})()[0]

library.properties()

// {"class":"source", "id":64, "index":1, "name":"Library", "persistentID":"2D8F973150E0A3AD", "kind":"library", "capacity":0, "freeSpace":0}

请注意在 who 子句之后添加 () 以将对象说明符解析为引用数组,然后 [0] 以获取第一个(在我的情况下也是唯一的)库对象引用,然后可以使用它来获取该库的属性。

如果源在其他语言或地区没有被命名为“图书馆”,我可能会改用这个:

library = Application("iTunes").sources.whose({kind:"kLib"})()[0]
于 2016-07-11T20:19:19.500 回答