2

I have this piece of code and ran it through JSLint to make sure everything is according to best practices. It's basically a custom feature detection.

(function() {
var vendorArray = ['', '-webkit-'],
    vendorIndex = vendorArray.length,
    mergedProperty,
    validProperty,
    activePrefix,
    detectorElement = document.createElement('detector'),
    detectorStyle = detectorElement.style,
    prefixRegex = new RegExp('%prfx%', 'g'),
    camelRegex = new RegExp('\-([a-z])', 'g'),
    propertyArray = [
        ['backgroundImage', 'background-image: %prfx%linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1)), %prfx%linear-gradient(rgba(0, 0, 0, 0.5) 1%, rgba(0, 0, 0, 0.5) 99%)'],
        ['boxShadow', 'box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, 0.5), inset 1px 1px 1px 1px rgba(0, 0, 0, 1)'],
        ['transition', '%prfx%transition: all 1s'],
        ['animation', '%prfx%animation: example 1s'],
        ['transform', '%prfx%transform: translate3d(1px, 1px, 1px)']
    ];

// property ist z.B. propertyArray[0] also das erste Property im Array; mit prefix kann man angeben ob das js Attribut ein Vendor-Prefix benötigt - 0 oder 1
function vendorCheck(property, prefix) {
    // Zur Sicherheit löschen wir das gesamte style-Attribut zu Beginn
    if (detectorElement.getAttribute('style')) {
        detectorElement.removeAttribute('style');
    }
    while (vendorIndex--) {
        // activePrefix cached den Index bzw. das Vendor-Prefix der Schleife z.b. -webkit-
        activePrefix = vendorArray[vendorIndex];
        // Das detector Element bekommt den Stil gesetzt >> property[1] = propertyArray[0][1] (propertyArray[0] wurde in die Funktion übergeben) >> im Stil wird der Platzhalter %prfx% mit dem jeweiligen aktiven Vendor-Prefix ersetzt
        detectorStyle.cssText = property[1].replace(prefixRegex, activePrefix);
        // Überprüfen ob das Attribut z.b. transition einen Vendor-Prefix erhalten soll, z.B. WebkitTransition
        if (prefix === 1) {
            // Aus dem String mergedProperty z.b. -webkit-transition wird -w und -t extrahiert und in Großbuchstaben zurückgegeben
            mergedProperty = activePrefix + property[0];
            validProperty = mergedProperty.replace(camelRegex, function(match, p1) {
                return p1.toUpperCase();
            });
        }
        // Wird prefix nicht übergeben, ist das Attribut gleich dem Attribut aus propertyArray
        else {
            validProperty = property[0];
        }
        // Wenn das detector Element der angewendeten Stil behalten hat, also das Attribut validProperty = property[0] = propertyArray[0][0] true ist, wird z.b. das Attribut WebkitTransition zurückgegeben und die Schleife beendet
        if (detectorStyle[validProperty]) {
            return validProperty;
        }
    }
};

document.getElementsByTagName('body')[0].innerHTML = detectorStyle[vendorCheck(propertyArray[4], 1)];

}());

However JSLint tells me that this part has some issues, since I'm declaring a function within a loop:

validProperty = mergedProperty.replace(camelRegex, function(match, p1) {
                return p1.toUpperCase();
            });

Is there a way to have a named callback function that is outside the loop?

Find a Codepen here: http://codepen.io/lieferant/pen/kXJLjJ

3
  • 3
    "I have this piece of code and ran it through JSLint to make sure everything is according to best practices" JSLint != best practices. JSLint == Douglas Crockford's opinions about best practices, frequently not broadly-shared. Commented Jul 24, 2016 at 13:42
  • Apart from what someone might think about Mr. Crockford, it makes sense to not declare a function within loops. Commented Jul 24, 2016 at 13:44
  • Creating functions within loops isn't a special case; like most things, it depends. For instance, your code as quoted is clear, won't run into the closure within loops problem, is easily maintained, and will get optimized by the JavaScript engine if necessary. Sometimes it makes sense to do what you've done; other times it makes sense to put it in a named function and reuse it. Commented Jul 24, 2016 at 13:48

1 Answer 1

2

Is there a way to have a named callback function that is outside the loop?

Yes, just declare it within your function, and call it:

function vendorCheck(property, prefix) {

    // ...

    while (/*...*/) {
        validProperty = mergedProperty.replace(capitalizeFirstCaptureGroup);
    }

    // ...

    function capitalizeFirstCaptureGroup(match, p1) {
        return p1.toUpperCase();
    }

    // ...
}

It can be at the top or bottom. It should be at the top level of the function, not within any control blocks. (As of ES2015, it's valid if it's inside a control block, but the rules are...complicated.)

Although actually, that one is general enough you might put it in a general utilities area and use it more broadly than just within vendorCheck.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.