Использование "чьих" для массивов в Javascript для автоматизации
Игра с новым JS для автоматизации с помощью Script Editor. Я получаю сообщение об ошибке в последней строке следующего:
var iTunes = Application("iTunes");
var sources = iTunes.sources();
var library = sources.whose({name : "Library"});
Подтверждено, что массив источников соответствует ожиданиям (два элемента, один с name
"Библиотека" и один "Интернет-радио"). Но эта последняя строка задыхается от Error on line 3: TypeError: undefined is not a function (evaluating 'sources.whose({name : "Library"})')
,
Насколько я могу судить, я использую правильный синтаксис для whose
функция (Я тоже пробовал с явным _equals
пункт к тому же результату.) Что я делаю не так?
4 ответа
Теперь это работает так, как предсказывает теория.
(function () {
'use strict';
var iTunes = Application('iTunes'),
filtered = iTunes.sources.whose({
name: 'Library'
});
return filtered().length;
})();
Что я делаю неправильно?
Короткий ответ: это не твоя вина. Документация 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 на основе событий основаны на удаленных вызовах процедур и простых первоклассных запросах. Это не ООП, независимо от внешнего вида: это просто синтаксический сахар, облегчающий чтение и запись запросов.
...
В этом случае ваша вторая строка говорит iTunes, чтобы получить список (массив) объектов запроса (ObjectSpecifiers), которые идентифицируют каждый из source
объекты в вашем приложении iTunes:
var iTunes = Application("iTunes");
var sources = iTunes.sources();
Получив массив, вы не сможете использовать его для создания дальнейших запросов, поскольку JavaScript сам не знает, как создавать запросы. То, что вы на самом деле хотите, это:
var iTunes = Application("iTunes");
var sourcesSpecifier = iTunes.sources;
var librarySpecifier = sourcesSpecifier.whose({name : "Library"});
Это даст вам спецификатор объекта, который идентифицирует все source
объекты, чье имя "Библиотека". (Если вы хотите указать только первый source
объект с именем "Библиотека", используйте byName
метод вместо whose
; это проще.)
-
Лично я считаю, что все это несколько академично, поскольку реализация моста событий Apple в JXA, как и его документация, в любом случае в основном состоит из Lame и Fail. Это в основном работает до определенного момента, а затем обрушивается на вас за это. Если ваши потребности скромны и "достаточно хороши", чтобы сделать вас более мощным, но для чего-то нетривиального, придерживайтесь AppleScript: это единственное поддерживаемое решение, которое работает правильно.
(У команды AppleScript/JXA также нет оправдания такой дерьмовой работе: несколько месяцев назад я отправил им почти законченную эталонную реализацию JavaScriptOSA для изучения или кражи по своему усмотрению, которую они полностью проигнорировали. это была давно решенная проблема.)
В 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]
Основано на примечаниях к выпуску JavaScript для автоматизации Mail.inbox.messages.whose(...)
Например, должно работать следующее:
var iTunes = Application('iTunes');
var filtered = iTunes.sources.whose({name : 'Library'});
Кажущаяся цель для whose
Метод "с" объектом, содержащим запрос "должен быть эффективным, только внося выбранные элементы (или ссылки на элементы) из иерархии объектов OS X в результирующий массив JavaScript.
Тем не менее whose
особенность JXA, по-видимому, имела некоторые ошибки в более раннем выпуске OS X v10.10.
Таким образом, поскольку рассматриваемый массив небольшой (т.е. 2 элемента), фильтрация может выполняться быстро и надежно на стороне JavaScript после получения элементов в виде массива JS.
Обходной пример 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);