Dieses Dokument erläutert die Syntaxunterschiede der Expression-Sprachen zwischen den Expression-Engines für JavaScript und das veraltete ExtendScript in After Effects 16.0.

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 JavaScripts: Es wurden Verbesserungen an der Expression-Sprache vorgenommen.

Expressions können JavaScript-Syntax von ECMAScript 2018 verwenden.

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:

Zusätzliche empfohlene und detaillierte Ressourcen zum Erlernen von JavaScript:

„.value“ ist bei Verknüpfung mit anderen Eigenschaften aus dem Quelltext nicht mehr erforderlich

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.

Einfrieren von Eigenschaftswerten mit „posterizeTime(0)“

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.

Inkompatible veraltete Syntax

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.

Syntaxunterschiede für if/else-Anweisungen

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.

Beenden einer Expression mit einer if-Anweisung ohne else-Anweisung ist nicht zulässig

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;
}

Dies wird in beiden Engines korrekt ausgewertet.

„if“ und „else“ dürfen nicht ohne Klammern in derselben Zeile stehen

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.

Expressions dürfen nicht mit einer Funktionsdeklaration enden

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;

Bei Verwendung der Engine für JavaScript muss dies durch „thisLayer“ ersetzt werden:

thisLayer(5)(2).value;

thisLayer ist mit beiden Expression-Engines kompatibel.

Für den Array-Index-Zugriff der Eigenschaft „Quelltext“ auf Zeichen ist „.value“ erforderlich

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.

Diese Syntax ist mit beiden Engines kompatibel.

Snake-Case-Eigenschaften und -Methoden sind nicht zulässig

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()

Verwenden von „eval()“ mit binär codierten (.jsxbin)-Expressions

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.

Eingeschränkte Unterstützung für das Objekt „$.“ (Dollar)

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

Keine Unterstützung für „...reflect.properties“, „...reflect.methods“ und „toSource()“

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

Ersetzen mathematischer Operatoren durch vektormathematische Funktionen

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 );

Dieses Werk unterliegt den Bedingungen der Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.  Twitter™- und Facebook-Beiträge fallen nicht unter die Bedingungen der Creative Commons-Lizenz.

Rechtliche Hinweise   |   Online-Datenschutzrichtlinie