In diesem Dokument erfahren Sie, wie Sie Ihre Expressions für die Expression-Engine für JavaScript verbessern oder Fehler beheben, die auftreten, wenn für vorherige Versionen von After Effects geschriebene Expressions nicht in der Expression-Engine für JavaScript ausgewertet werden können.
Die After Effects-Expression-Sprache basiert auf JavaScript, bei welchem es sich um eine Implementierung von ECMAScript handelt. Die Expression-Engine für JavaScript in After Effects 16.0 basiert auf ECMAScript 2018. Die Expression-Engine für das veraltete ExtendScript basiert auf ECMAScript 3 (1999). (Adobe ExtendScript ist außerdem die Sprache, die für die Skripterstellung in After Effects und anderen Adobe-Applikationen verwendet wird.)
Sie können die unten aufgeführten Beispiele sowie die Anleitungen zum Erstellen von Expressions heranziehen, die sich für die Expression-Engines für JavaScript und das veraltete ExtendScript gleichermaßen eignen.
Wesentliche Unterschiede zwischen den Expression-Engines für JavaScript und das veraltete ExtendScript:
- Syntax des modernen JavaScript: Ergänzungen für JavaScript in ECMAScript 5 durch ECMAScript 2018 ermöglichen neue Syntax und Methoden für Expressions bei Verwendung der Expression-Engine für JavaScript. Außerdem wurden einige kleine Verbesserungen an der Expression-Syntax bei Verwendung der Expression-Engine für JavaScript vorgenommen. Wesentliche Unterschiede:
- Inkompatible veraltete Syntax: Einige Teile der veralteten Syntax sind nicht mit der Expression-Engine für JavaScript kompatibel. Diese Ausnahmen sind hier zusammen mit den Änderungen dokumentiert, die vorgenommen werden müssen, um die Kompatibilität der betreffenden Syntax mit der Engine für JavaScript sicherzustellen. Wesentliche Unterschiede:
- Die Syntax für if/else-Anweisungen unterscheidet sich.
- „if“ und „else“ dürfen nicht ohne Klammern in derselben Zeile stehen.
- Expressions dürfen nicht mit einer Funktionsdeklaration enden.
- Die „this()“-Kurznotationssyntax ist nicht zulässig, stattdessen empfiehlt sich die Verwendung von „thisLayer()“.
- Für den Array-Index-Zugriff der Eigenschaft „Quelltext“ auf Zeichen ist „.value“ erforderlich.
- Snake-Case-Eigenschaften und -Methoden sind nicht zulässig.
- „eval()“ wird mit binär codierten (.jsxbin)-Expressions verwendet.
- Es besteht nur eingeschränkte Unterstützung für das Objekt „$.“ (Dollar).
- „...reflect.properties“, „...reflect.methods“ und „toSource()“ werden nicht unterstützt.
- Syntaxanforderungen für .jsx-Bibliotheken für Expressions und „eval()“: Bei der Verwendung von Expressions innerhalb einer .jsx-Funktionsbibliothek für Expressions oder wenn eine Expression innerhalb von eval() aufgerufen wird, müssen thisLayer. und thisProperty. explizit abgerufen und mathematische Operationen an Arrays müssen durch Vektorberechnungen ersetzt werden. Wesentliche Unterschiede:
Die JavaScript-Sprache wurde seit Einführung von ECMAScript 3 vielfach ergänzt. Es gibt neue Methoden zur Verwendung mit Zeichenfolgen, Arrays und Objekten, die kompakter und besser lesbar sind, und neue Möglichkeiten, um u. a. Variablen und Funktionen sowie Standardparameter und Spread-Operatoren zu deklarieren. In diesem Dokument wird nicht näher auf diese Änderungen eingegangen, da sie allgemein für die JavaScript-Sprache gelten. Weitere Informationen zu den zahlreichen Syntaxergänzungen finden Sie unter den folgenden Links:
- Leitfaden zu JavaScript ES5 (alias ECMAScript 5)
- Neue Arraymethoden
- Neue Objektmethoden
- JSON.stringify() und JSON.parse()
Zusätzliche empfohlene und detaillierte Ressourcen zum Erlernen von JavaScript:
Wenn Sie einen anderen Eigenschaftswert aus einer Quelltext-Eigenschaft referenzieren, muss für die Expression-Engine für das veraltete ExtendScript .value am Ende der Eigenschaft hinzugefügt werden. Die Engine für JavaScript zeigt standardmäßig den Wert der Eigenschaft an, sofern nicht explizit ein anderes Attribut wie .propertyIndex oder .name verwendet wird.
Beispiel:
thisComp.layer("Solid 1").transform.position // In the Legacy engine, this evaluates to "[object Property]" when applied to a Source Text property. // In the JavaScript engine, this evaluates to the value of the Position property of layer "Solid 1" when applied to a Source Text property.
In After Effects 16.0 wird mit posterizeTime(0) der Eigenschaftswert zum Zeitpunkt „0“ in der Komposition eingefroren. Dies gilt für die Expression-Engines für JavaScript und das veraltete ExtendScript gleichermaßen.
Hinweis:
Diese Funktion ist nicht abwärtskompatibel und kann in After Effects-Versionen vor Version 16.0 zu unerwarteten Ergebnissen führen.
Fast die gesamte Syntax der Expression-Engine für das veraltete ExtendScript ist mit der Expression-Engine für JavaScript kompatibel. Einige Teile der veralteten Syntax sind jedoch nicht kompatibel. Dies liegt einerseits daran, dass das moderne JavaScript Syntaxänderungen aufweist, und anderseits daran, dass veraltete Syntax entfernt wurde. Beispiele für nicht funktionierende und funktionierende Syntax sind im Folgenden aufgeführt.
Die meisten dieser Syntaxunterschiede können durch Applikationsskripterstellung korrigiert werden, bei der die Expressions neu geschrieben werden.
Im Allgemeinen empfiehlt es sich, if/else-Anweisungen gemäß den MDN-Richtlinien immer mit Zeilenumbrüchen und Klammern zu schreiben. Während die Expression-Engine für das veraltete ExtendScript Abweichungen bei if/else-Anweisungen tolerierte, ist die Engine für JavaScript diesbezüglich strikt. Eine fehlerhafte if/else-Syntax kann bei Verwendung der Engine für JavaScript nicht ausgewertet werden.
Wenn eine Expression mit einer if-Anweisung ohne eine else-Anweisung endet, kann die JavaScript-Engine die Expression nicht auswerten, was zur Fehlermeldung „In der Expression wird ein nicht definierter Wert verwendet (u. U. liegt das Subscript des Arrays außerhalb des gültigen Bereichs?)“ führt. Bei Verwendung der Engine für das veraltete ExtendScript wird für die folgende Expression der Wert „100“ festgelegt, wenn der Zeitraum länger als eine Sekunde ist. Andernfalls wird der Wert auf „50“ festgelegt:
var x = 50; if ( time > 1 ) { x = 100 } // The "else" here is implied but not stated.
Bei Verwendung der Engine für JavaScript ist die explizite Angabe des Teils else der Anweisung erforderlich, wenn es sich dabei um die letzte Anweisung in der Expression handelt:
var x = 50; if ( time > 1 ) { x = 100; } else { x; }
Eine if/else-Anweisung in einer einzelnen Zeile ohne Klammern wird zwar von der Engine für das veraltete ExtendScript ausgewertet, bei Verwendung der Engine für JavaScript führt dies jedoch zu einer Fehlermeldung wie „Syntaxfehler: unerwarteter Token 'else'“ oder „In der Expression wird ein nicht definierter Wert verwendet (u. U. liegt das Subscript des Arrays außerhalb des gültigen Bereichs?)“. Die Fehlermeldung kann je nach Kontext und Eigenschaftstyp abweichen.
Bei Verwendung der Engine für das veraltete ExtendScript wird für die folgende Expression der Wert „100“ festgelegt, wenn der Zeitraum länger als eine Sekunde ist. Andernfalls wird der Wert auf „50“ festgelegt:
if ( time > 1 ) 100 else 50;
Bei Verwendung der Engine für JavaScript sind für die Auswertung von if/else-Anweisungen Zeilenumbrüche oder Klammern erforderlich. In einfachen Fällen kann stattdessen auch der ternäre Operator verwendet werden. Folgende Syntax kann bei Verwendung der Engine für JavaScript verwendet werden:
// Solution A: adding a line break before "else" will allow both engines to evaluate correctly. if ( time > 1 ) 100 else 50; // Solution B: adding correct bracketing will also allow both engines to evaluate correctly. if ( time > 1 ) { 100 } else { 50 }; // Solution C: Use a ternary operator in place of the if...else statement, which also evaluates correctly in both engines. time > 1 ? 100 : 50;
Sämtliche der oben aufgeführten Lösungen werden bei Verwendung der Expression-Engines für JavaScript und das veraltete ExtendScript gleichermaßen korrekt ausgewertet.
Wenn eine Expression mit einer Funktionsdeklaration endet, kann die Engine für JavaScript die Expression nicht auswerten, was zur Fehlermeldung „Objekt vom Typ X vorgefunden; eine Zahl, ein Array oder eine Eigenschaft wurde benötigt“ führt. Bei Verwendung der Engine für JavaScript muss das zuletzt ausgewertete Element einen Wert zurückgeben, anstatt einen Wert zu deklarieren.
Das folgende Beispiel funktioniert nur bei Verwendung der Engine für das veraltete ExtendScript:
timesTen( value ); // The Legacy engine evaluates this line, even though the function is declared below. function timesTen ( val ) { return val * 10 }
Wenn eine Funktion als letzte Zeile (anstelle der Deklaration) aufgerufen wird, wird die Expression in beiden Engines korrekt ausgewertet:
function timesTen ( val ) { return val * 10 } timesTen( value ); // The JavaScript engine needs the function call to happen below the declaration in order to return the correct value.
„this()“-Kurznotationssyntax ist nicht zulässig, stattdessen empfiehlt sich die Verwendung von „thisLayer()“
Bei Verwendung der Engine für das veraltete ExtendScript konnte this als Kurznotation für thisLayer verwendet werden. Bei Verwendung der Engine für JavaScript bezieht sich this jedoch auf das globale Objekt. Stattdessen muss thisLayer verwendet werden, Die Verwendung von this führt zur Fehlermeldung Dies ist keine Funktion.
Im folgenden Beispiel für die Engine für das veraltete ExtendScript wird this für die Erstellung einer kompakten Verknüpfung von der Eigenschaft „Quelltext“ zu einer Eigenschaft „Textebenenposition“ verwendet:
this(5)(2).value;
thisLayer(5)(2).value;
Bei Verwendung der Engine für das veraltete ExtendScript konnte auf die Zeichen einer Quelltext-Eigenschaft mit einer Klammernotation wie auf ein Array zugegriffen werden:
text.sourceText[0] // Returns the first character of the Source Text property's text value.
Bei Verwendung der Engine für JavaScript muss .value hinzugefügt werden, um auf die Zeichen zuzugreifen:
text.sourceText.value[0] // Returns the first character of the Source Text property's text value.
Die veralteten Snake-Case-Eigenschaften und -Methoden (bei denen ein Unterstrich anstelle von Binnenversalien verwendet wird) werden von der Engine für JavaScript nicht unterstützt. Stattdessen sollten die camelCase-Versionen verwendet werden, da sie mit beiden Engines kompatibel sind. In der nachfolgenden Liste sind alle veralteten Snake-Case-Fälle und die entsprechenden camelCase-Versionen aufgeführt.
Snake-Case-Eigenschaften | camelCase-Eigenschaften | Snake-Case-Methoden | camelCase-Methoden |
this_comp this_layer this_property color_depth has_parent in_point out_point start_time has_video has_audio audio_active anchor_point audio_levels time_remap casts_shadows light_transmission accepts_shadows accepts_lights frame_duration shutter_angle shutter_phase num_layers pixel_aspect point_of_interest depth_of_field focus_distance blur_level cone_angle cone_feather shadow_darkness shadow_diffusion active_camera |
thisComp thisLayer thisProperty colorDepth hasParent inPoint outPoint startTime hasVideo hasAudio audioActive anchorPoint audioLevels timeRemap castsShadows lightTransmission acceptsShadows acceptsLights frameDuration shutterAngle shutterPhase numLayers pixelAspect pointOfInterest depthOfField focusDistance blurLevel coneAngle coneFeather shadowDarkness shadowDiffusion activeCamera |
value_at_time() velocity_at_time() speed_at_time() nearest_key() posterize_time() look_at() seed_random() gauss_random() ease_in() ease_out() rgb_to_hsl() hsl_to_rgb() degrees_to_radians() radians_to_degrees() from_comp_to_surface() to_comp_vec() from_comp_vec() to_world_vec() from_world_vec() to_comp() from_comp() to_world() from_world() temporal_wiggle() loop_in_duration() loop_out_duration() loop_in() loop_out () |
valueAtTime() velocityAtTime() speedAtTime() nearestKey() posterizeTime() lookAt() seedRandom() gaussRandom() easeIn() easeOut() rgbToHsl() hslToRgb() degreesToRadians() radiansToDegrees() fromCompToSurface() toCompVec() fromCompVec() toWorldVec() fromWorldVec() toComp() fromComp() toWorld() fromWorld() temporalWiggle() loopInDuration() loopOutDuration() loopIn() loopOut() |
Expressions, die im ExtendScript-Binärformat codiert sind (gespeichert als binäre .jsxbin-Datei aus ExtendScript ToolKit CC), werden von der Engine für JavaScript nicht unterstützt.
Wenn Sie eine Expression verschleiern möchten, verwenden Sie die Engine für das veraltete ExtendScript oder eine andere Verschleierungsmethode, die mit ECMAScript 2018 kompatibel ist. Einige Verschleierungsmethoden sind möglicherweise nicht mit beiden Expression-Engines kompatibel.
Die Methoden und Eigenschaften für das Objekt „$.“ (Dollar) sind ExtendScript-spezifisch und werden größtenteils nicht von der Engine für JavaScript unterstützt. In dieser Tabelle werden nicht unterstützte und unterstützte Anwendungsfälle für dasObjekt „$.“ (Dollar) aufgeführt:
Nicht unterstützt | Unterstützt |
$.fileName $.hiResTimes $.stack $.evalFile() $.list() $.setenv() $.getenv() $.appEncoding $.buildDate $.decimalPoint $.dictionary $.error $.flags $.includePath $.level $.line $.locale $.localize $.memCache $.os $.screens $.strict $.version |
$.build $.engineName (wird von der Engine für das veraltete ExtendScript nicht unterstützt) $.global |
reflect.properties und reflect.methods werden von der Engine für JavaScript nicht unterstützt, da es sich um ExtendScript-spezifische Methoden handelt, für die es keine direkten Entsprechungen in JavaScript gibt.
toSource() in JavaScript ist veraltet und nicht Teil eines Standards Tracks.
Um eine Liste der verfügbaren Eigenschaften und Methoden für eine bestimmte After Effects-Eigenschaft anzuzeigen, die dem entspricht, was durch die oben aufgeführten Methoden bereitgestellt wurde, verwenden Sie die folgende Expression für eine Quelltext-Eigenschaft und verknüpfen Sie sie mit der gewünschten Eigenschaft, z. B. indem Sie das Auswahlwerkzeug anstelle von thisProperty in Zeile 1 verwenden:
let obj = thisProperty; // Replace "thisProperty" with a property-link to your desired property. let props = []; do { Object.getOwnPropertyNames(obj).forEach(prop => { if (props.indexOf(prop) === -1) { props.push(prop); } }); } while (obj = Object.getPrototypeOf(obj)); props.join("\n"); // Returns an array of strings listing the properties and methods available.
Die oben aufgeführte Expression ist nicht mit der Engine für das veraltete ExtendScript kompatibel. Sie verwendet Syntax und Methoden, die nicht in ECMAScript 3 verfügbar sind.
Syntaxanforderungen für .jsx-Bibliotheken für Expressions und „eval()“ bei Verwendung der Engine für JavaScript
Bei der Verwendung von Expressions innerhalb einer .jsx-Funktionsbibliothek für Expressions oder wenn eine Expression innerhalb von eval() aufgerufen wird, muss eine bestimmte Syntax geändert werden:
Ein explizites thisLayer.- oder thisProperty.-Präfix muss zu allen nativen Methoden oder Attributen hinzugefügt werden, die nicht explizit für eine Ebene oder Eigenschaft aufgerufen werden. Durch das Präfix erhält die Engine für JavaScript die Information, für welches Objekt Sie die Methode oder das Attribut aufrufen.
Mathematische Operationen an Arraywerten wie „Position“ müssen mithilfe von vektormathematischen Methoden oder Schleifenfunktionen berechnet werden, um auf jedes Element im Array angewendet zu werden. Überladene mathematische Operatoren wie „position + [100,100]“ werden nicht ausgewertet.
Bei Verwendung der Engine für JavaScript werden Expressions vor der Auswertung vorverarbeitet, um einen Teil der Expression-Syntax für das veraltete ExtendScript für die neue Engine lesbar zu machen. Diese Vorverarbeitungsaufgaben werden jedoch nicht ausgeführt, wenn Expressions aus einer .jsx-Funktionsbibliothek für Expressions ausgewertet werden oder wenn eine Expression innerhalb von eval() aufgerufen wird. Die oben genannten Syntaxänderungen müssen für diese Fälle manuell vorgenommen werden. Sämtliche dieser Syntaxänderungen sind mit der Engine für das veraltete ExtendScript abwärtskompatibel, sodass sich eine .jsx-Bibliothek für Expressions, die sich für die Verwendung mit der Engine für JavaScript eignet, auch für die Engine für das veraltete ExtendScript eignet.
Leistungstipp: Aufgrund der fehlenden Vorverarbeitung lässt sich mit dem Aufruf komplexer Expressions aus einer .jsx-Bibliothek mit dieser Syntax und der Engine für JavaScript im Vergleich zum direkten Aufruf derselben Expressions für eine Eigenschaft eine Leistungssteigerung erzielen.
Nativen Methoden und Attributen muss explizit „thisLayer.“ oder „thisProperty.“ vorangestellt werden
In der folgenden Tabelle sind die Methoden und Attribute aufgeführt, die ein Präfix erfordern. Beispielsweise muss „time“ als thisLayer.time geschrieben sein, wiggle() hingegen als thisProperty.wiggle().
Diese Präfixe werden nur dann benötigt, wenn das Attribut oder die Methode nicht bereits explizit für eine andere Ebene oder Eigenschaft aufgerufen wird. Beispielsweise ist beim Aufrufen von thisComp.layer(1).hasParent das Hinzufügen von thisLayer. nicht erforderlich, da .hasParent bereits explizit für layer(1) aufgerufen wird.
Methoden, für die thisLayer. erforderlich ist | Attribute, für die thisLayer. erforderlich ist | Methoden, für die thisProperty. erforderlich ist | Attribute, für die thisProperty. erforderlich ist |
comp() footage() posterizeTime() add() sub() mul() div() clamp() length() dot() normalize() cross() lookAt() timeToFrames() framesToTime() timeToTimecode() timeToFeetAndFrames() timeToNTSCTimecode() timeToCurrentFormat() seedRandom() random() gaussRandom() noise() degreesToRadians() radiansToDegrees() linear() ease() easeIn() easeOut() rgbToHsl() hslToRgb() hexToRgb() mask() sourceRectAtTime() sourceTime() sampleImage() toComp() fromComp() toWorld() fromWorld() toCompVec() fromCompVec() toWorldVec() fromWorldVec() fromCompToSurface() |
time source thisProject colorDepth transform anchorPoint position scale rotation opacity orientation rotationX rotationY rotationZ lightTransmission castsShadows acceptsShadows acceptsLights ambient diffuse specular specularIntensity shininess specularShininess metal audioLevels timeRemap marker name width height index parent hasParent inPoint outPoint startTime hasVideo hasAudio active enabled audioActive cameraOption pointOfInterest zoom depthOfField focusDistance aperature blurLevel irisShape irisRotation irisRoundness irisAspectRatio irisDiffractionFringe highlightGain highlightThreshold highlightSaturation lightOption intensity color coneAngle coneFeather shadowDarkness shadowDiffusion |
valueAtTime() velocityAtTime() speedAtTime() wiggle() temporalWiggle() smooth() loopIn() loopOut() loopInDuration() loopOutDuration() key() nearestKey() propertyGroup() points() inTangents() outTangents() isClosed() pointsOnPath() tangentOnPath() normalOnPath() createPath() |
velocity speed numKeys propertyIndex |
Die Engines für JavaScript und das veraltete ExtendScript ermöglichen beide das Überladen mathematischer Operatoren für Arrays durch die Verwendung von Syntax wie position + [100,100]. Dies gilt jedoch nicht für Expressions innerhalb einer .jsx-Funktionsbibliothek für Expressions oder innerhalb von eval().
Um Berechnungen für Arrayeigenschaften wie „Position“ und „Skalierung“ durchzuführen, sollten die vektormathematischen Entsprechungen für Addition, Subtraktion, Multiplikation und Division verwendet werden. Die vektormathematischen Funktionen eignen sich auch für reguläre Zahlen, sodass eine Funktion, die für Eigenschaften beider Datentypen aufgerufen werden kann, die vektormathematischen Funktionen verwenden sollte.
Hinweis:
Das Präfix thisLayer. muss mit den vektormathematischen Funktionen verwendet werden.
- Addition: thisLayer.add(vec1, vec2)
- Subtraktion: thisLayer.sub(vec1, vec2)
- Multiplikation: thisLayer.mul(vec, amount)
- Division: thisLayer.div(vec, amount)
Im Folgenden sind Beispiele für Expressions mit Standardberechnungen und aktualisierten Vektorberechnungen aufgeführt. Die vektormathematischen Expressions verwenden ggf. auch das entsprechende thisLayer.- oder thisProperty.-Präfix.
So suchen Sie nach Unterschieden zwischen einer wiggle()-Methode und dem Wert der einer Position-Eigenschaft:
// Standard Math: wiggle() - value; // Vector Math: thisLayer.sub( thisProperty.wiggle(), value );
So interpolieren Sie ähnlich wie bei linear() zwischen zwei Werten, jedoch mit einem erweiterten Bereich über das definierte Minimum und Maximum hinaus:
// Standard Math: value1 + ( ( t - tMin ) / ( tMax - tMin ) ) * ( value2 - value1 ); // Vector Math: thisLayer.add( value1, thisLayer.mul( thisLayer.div( thisLayer.sub( t, tMin ), thisLayer.sub( tMax, tMin ) ), thisLayer.sub( value2, value1 ) ) );
So veranlassen Sie die Wiederholung einer Position-Eigenschaft in Vorwärtsrichtung und in Rückwärtsrichtung:
// Standard Math: loopIn( "cycle" ) + loopOut( "cycle" ) - value; // Vector Math: thisLayer.sub( thisLayer.add( thisProperty.loopIn( "cycle" ), thisProperty.loopOut( "cycle" ) ), value );