I would strongly consider storing the various variables that define the transformation in a structured object like this:
var transformConfig = {
rotate: {
x: ...,
y: ...,
z: ...
},
scale: {
x: ...,
y: ...
},
translate: {
x: ...,
y: ...,
z: ...
},
skew: {
x: ...,
y: ...
}
};
That gives you the ability to easily iterate over this object to create transformation strings. An example of this iteration might be:
function createTranformString(transformConfig) {
// a variable to store array of individual transform strings
var transformStrings = [];
// store functions that build strings for each transform type
// not shown here but you may want to consider ECMA6 templating
var getString = {
rotate: function(rotate) {
for (dim in rotate) {
transformStrings.push('rotate' + dim + '(' + rotate[dim] + 'deg)';
}
},
scale: function(scale) {
scale.x = scale.x || 1;
scale.y = scale.y || 1;
transformStrings.push('scale(' + scale.x + ',' + scale.y + ')');
},
translate: function(translate) {
for (dim in translate) {
transformStrings.push('translate' + dim + '(' + translate[dim] + 'px)';
}
},
skew: function(skew) {
skew.x = skew.x || 0;
skew.y = skew.y || 0;
transformStrings.push('skew(' + skew.x + 'deg,' + skew.y + 'deg)');
}
}
// iterate the config object to generate strings
for (transformAction in transformConfig) {
var transform = transformConfig[transformAction];
getString[transformAction](transform);
}
return transformStrings.join(' ');
};
This approach would limit the repeat code you have for each transformation string and would also take care of your if concern in that only those transformation types specified in the config would be executed.
This also more directly injects the transformation configuration information into the function that generates the strings, meaning you no longer have to have to rely on variables that may or may not be present in inherited scope.
Since you are using ECMA6, I would also consider building this as a class (or classes).