#javascript #function #applescript
Вопрос:
Поэтому я пытался переделать некоторые Array.prototype
функции из Javascript в Applescript. Пытаясь это сделать, я заметил, что многие функции Javascript используют то, что, как мне кажется, называется функцией стрелки.
Вот небольшой обзор того, что я понимаю из этого:
Функции со стрелками строятся следующим образом (показано методом Array.prototype.filter()
-):
words.filter(word => word.length > 6);
^^^ ^^^ ^^^ ^^ ^^^
1 2 3 4 5
Пример взят из mozilla.org.
- Это указывает целевой массив/список. Легко реализовать в Applescript.
- Это определяет используемую встроенную функцию. Я понятия не имею, как заставить это работать, потому что я не знаю, как реализовать шаги 3, 4 и 5.
- Это присваивает значение, которое «назначено» каждому элементу в списке. Это можно было бы сделать статически с помощью чего-то вроде
repeat with word in words ...
(за исключением того факта, что эти слова зарезервированы.), но я не знаю способа сделать это динамически. - Это знак, который «указывает» компилятору, что должно произойти. Я не думаю, что это необходимо реализовывать.
- Это (в данном случае) сравнение того, имеет ли данное слово большее количество символов, равное 6. Это решает, должен ли предмет оставаться внутри или нет. Это можно было бы воссоздать с помощью
if count of characters of word > 6 then set end of someNewListWeCreatedOutsideThisLoop to word
.
Эти функции со стрелками также могут вместо сравнений иметь такие функции, как forEach()
:
array1.forEach(element => console.log(element));
Пример взят из mozilla.org.
Вот что я попробовал:
on myFunc(fn)
fn
end
myFunc(log "Hello World")
Это регистрирует «Привет, мир», а затем выдает ошибку о том, что было передано недостаточно параметров.
Вот немного хитрого обходного пути с использованием командной строки:
set theWords to {"These", "are", "Words."}
forEach(theWords, "theWord => display dialog theWord")
on forEach(theArray, arrowFunction)
set AppleScript's text item delimiters to " => "
set arrowFunction to text items of arrowFunction
set AppleScript's text item delimiters to " "
return (do shell script "osascript -e 'repeat with " amp; item 1 of arrowFunction amp; " in (every word of "" amp; (theArray as string) amp; "")' -e '" amp; item 2 of arrowFunction amp; "' -e 'end repeat'")
end forEach
Этот метод работает, но у него утомительный синтаксис, скорость работы низкая, и я почти уверен, что упустил какой-то стильный метод Applescript.
Комментарии:
1. Сам по себе AppleScript является довольно минимальным языком и не имеет таких функций, как функции фильтрации или возможность передачи блоков. Вам нужно будет создать свой собственный обработчик(ы), используя функции, которые есть в языке AppleScript , чтобы выполнить эквивалент определенной функции.
2. Вместо того, чтобы пытаться реализовать функции из JavaScript в AppleScript, почему бы просто не использовать JavaScript? У него гораздо больше функций (ну, почти все работает), и в качестве бонуса его также можно использовать в редакторе сценариев.
3. @red_menace Мне нравится JavaScript, и я регулярно его использую, но я не попал в JXA, так как документация не так хороша, и я просто люблю Applescript.
4. @red_menace: JXA-мертвый продукт. Его поддержка событий Apple отключена, нет никакой документации или поддержки, которая стоила бы гроша, и он не интегрирован с остальной экосистемой JavaScript (узла). JXA так сильно провалилась, что Apple распустила команду автоматизации Mac и уволила ответственного за это премьер-министра. AppleScript-не очень хороший язык, но это единственный номинально поддерживаемый вариант, который работает правильно. (Для тех, кто любит жить опасно, python appscript и SwiftAutomation все еще работают, но я не предоставляю поддержку ни для того, ни для другого. NodeAutomation нарушена из-за bitrot в стороннем модуле NodObjC.)
5. Для тех, кто менее знаком с JS,
word => word.length > 6
это просто синтаксический сахар дляfunction (word) {return word.length > 6}
, который является традиционным синтаксисом JS для анонимных (т. Е. безымянных) функций. Оно более лаконично, но смысл точно такой же.
Ответ №1:
Оберните обработчик, содержащий ваше пользовательское поведение, в объект сценария. Затем вы можете передать объект сценария в качестве параметра другому обработчику и вызвать его там.
script Foo
to doStuff(a, b)
return a b
end doStuff
end script
to bar(obj)
obj's doStuff(1, 2)
end bar
bar(Foo)
--> 3
ETA: Фильтрация списка в JavaScript:
[1, 4, 6, 2].filter(function (n) {return n < 3})
// [ 1, 2 ]
Фильтрация списка в AppleScript (с помощью библиотеки списков):
use script "List"
script FilterObj
to filterItem(n)
return n < 3
end filterItem
end script
filter list {1, 4, 6, 2} using FilterObj
--> {1, 2}
AppleScript более подробен, но они функционально эквивалентны.
Комментарии:
1. Как это поможет в фильтрации списка для определенных элементов или вызове метода для каждого элемента в списке?
2. Примеры можно найти здесь , например
search text
filter list
,sort list
команды.3. Спасибо, что указали мне на это. Я и не знал, что такое существует.
4. Было бы интересно посмотреть, как вы будете реализовывать эту конкретную задачу фильтрации списков. Потому что я мало что знаю о тонкостях JavaScript.
Ответ №2:
Обновленный ответ. Я думаю, что теперь это точный эквивалентный пример закрытия JXA.
on wordsFilter(theWords, function) -- this is your prototype
if text 1 thru 19 of function is not "words whose length " then error
set compareSign to text 20 thru 21 of function
if compareSign is not in {"> ", "< "} then error
set N to (text 22 thru -1 of function) as integer
set filteredList to {}
script One -- this creates closure like in the Javascript
repeat with anItem in theWords
if length of anItem > N then set end of filteredList to contents of anItem
end repeat
return filteredList
end script
script Two -- other closure
repeat with anItem in theWords
if length of anItem < N then set end of filteredList to contents of anItem
end repeat
return filteredList
end script
if compareSign is "> " then return (run One)
if compareSign is "< " then return (run Two)
end wordsFilter
set theWords to {"ThisIsGreaterThan6", "are", "otherBigWord"}
wordsFilter(theWords, "words whose length > 6")
Комментарии:
1. Поскольку
prototype
обработчику передается только результат отfilterList
обработчика, чем это отличается от простого вызоваfilterList
обработчика в первую очередь?2. Хотя это позволяет вызывать одну функцию внутри другой и позволяет фильтровать списки по длине слов, это не позволяет пользователю фильтровать более сложные вещи, такие как, например, проверка того, содержит ли слово подстроку или другие вещи. Я думаю, что тогда это невозможно, ха.
3. RE: @red_menace: Насколько я понимаю, разница чисто эстетическая. Под именем функции прототипа вы получаете группу обработчиков, выполняющих аналогичные задачи. Но, может быть, я ошибаюсь и есть другие преимущества.
4. OP спрашивает, как передавать функции, которые в JS являются замыканиями , в качестве аргументов другим функциям. Обработчики AppleScript не являются закрытиями (они не фиксируют свою лексическую область, поэтому их нельзя безопасно передавать); однако объекты сценария AppleScript запоминают свою область и могут быть созданы и переданы как объекты первого класса. Объектная система AppleScript здесь аналогична Smalltalk/Obj-C (1.0) в том, что вы создаете объекты и вызываете обработчики (методы) для этих объектов. Библиотеки AS, которые я связал выше, показывают, как это сделать правильно.
5. @foo, я обновил свой ответ в соответствии с вашей заметкой об областях применения.