Handlebars.js: рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд "рдкреНрд░рддреНрдпреЗрдХ" рд╕рд╣рд╛рдпрдХ рдореЗрдВ рдорд╛рдирдЪрд┐рддреНрд░, рд╕реЗрдЯ рдФрд░ рдХрд╕реНрдЯрдо рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди?

рдХреЛ рдирд┐рд░реНрдорд┐рдд 10 рдЬрдире░ 2018  ┬╖  6рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: handlebars-lang/handlebars.js

ES6 рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ Handlebars рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп, рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд each рд╕рд╣рд╛рдпрдХ рдХреА рдХреЗрд╡рд▓ рд╕рд░рдгрд┐рдпреЛрдВ рдФрд░ рд╕рд╛рдорд╛рдиреНрдп рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреА рд╕реАрдорд╛ рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛ рдЬрд╛рддреА рд╣реИред рдЗрд╕ рдкрд░ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ each рд╣реЗрд▓реНрдкрд░ рдХреЗ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджрд┐рдпрд╛ рдЬреЛ рд╕рд░рдгрд┐рдпреЛрдВ, рдорд╛рдирдЪрд┐рддреНрд░реЛрдВ, рд╕реЗрдЯреЛрдВ, рдХрд╕реНрдЯрдо рдкреБрдирд░рд╛рд╡рд░реНрддрдиреАрдп рд╡рд╕реНрддреБрдУрдВ рдФрд░ рд╕рд╛рдорд╛рдиреНрдп рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред рд╡рд╣ рд╕рд╣рд╛рдпрдХ рдиреАрдЪреЗ рд╣реИред

рдХреНрдпрд╛ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд each рд╕рд╣рд╛рдпрдХ рдореЗрдВ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреА рд╕реВрдЪрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рд╢реБрд░реВ рдХрд░рдиреЗ рдХреА рдХреЛрдИ рдпреЛрдЬрдирд╛ рдпрд╛ рдЗрдЪреНрдЫрд╛ рд╣реИ? рдореИрдВ рдкреВрдЫрддрд╛ рд╣реВрдВ рдХреНрдпреЛрдВрдХрд┐ рдореИрдВ рд╕рдордЭрддрд╛ рд╣реВрдВ рдХрд┐ рд╣реИрдВрдбрд▓рдмрд╛рд░реНрд╕ рдХрд╛ рдЙрджреНрджреЗрд╢реНрдп рдкреЙрд▓реАрдлрд┐рд▓ рд╕реЗ рдмрдЪрдирд╛ рд╣реИ рдФрд░ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╕рдорд░реНрдерди рдкрд░ рд╕рдордЭреМрддрд╛ рдХрд┐рдП рдмрд┐рдирд╛ рдирдП рд╕рд╣рд╛рдпрдХ рдХреЛ рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдПрдХрдорд╛рддреНрд░ рддрд░реАрдХрд╛ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЗ рдореВрд▓ рдпрд╛ рдкреНрд░реА-рдкреЙрд▓реАрдлрд┐рд▓реНрдб рд╕рдорд░реНрдерди рдкрд░ рдирд┐рд░реНрднрд░ рд╡рд┐рднрд┐рдиреНрди рд╕реВрдЪреА рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд▓рд┐рдП рдЙрддреНрддрд░реЛрддреНрддрд░ рд╕рдорд░реНрдерди рдХреЛ рд╕рдХреНрд╖рдо рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред Set , Map , рдФрд░ Symbol рдХреЗ рд▓рд┐рдПред

Handlebars.registerHelper("each", function (contexts, options) {

    // Throw a runtime exception if options were not supplied.
    if (!options) {
        throw new Handlebars.Exception("Must pass iterator to #each");
    }

    // If the "list of contexts" is a function, execute it to get the actual list of contexts.
    if (typeof contexts === "function") {
        contexts = contexts.call(this);
    }

    // If data was supplied, frame it.
    const data = options.data ? Object.assign({}, options.data, { _parent: options.data }) : undefined;

    // Create the string into which the contexts will be handled and returned.
    let string = "";

    // Create a flag indicating whether or not string building has begun.
    let stringExtensionStarted = false;

    // Create a variable to hold the context to use during the next string extension. This is done to
    // allow iteration through the supplied list of contexts one step out of sync as they are looped
    // through later in this helper, ensuring a predictable sequence of value retrieval, string
    // extension, value retrieval, string extension...
    let nextContext;

    // Create a function responsible for expanding the string.
    const extendString = (final = false) => {

        // If other contexts have been encountered...
        if (nextContext) {

            // Expand the string using the block function.
            string += options.fn(nextContext.value, {
                data: data ? Object.assign(data, {
                    index: nextContext.index,
                    key: nextContext.key,
                    first: !stringExtensionStarted,
                    last: final
                }) : undefined,
                blockParams: [nextContext.key, nextContext.value]
            });

            // Note that string extension has begun.
            stringExtensionStarted = true;

        // If no contexts have been encountered and this is the final extension...
        } else if (final) {

            // Expand the string using the "else" block function.
            string += options.inverse(this);

        }

    };

    // If a list of contexts was supplied...
    if (contexts !== null && typeof contexts !== "undefined") {

        // Start a counter.
        let index = 0;

        // If an array list was supplied...
        if (Array.isArray(contexts)) {

            // For each of the possible indexes in the supplied array...
            for (const len = contexts.length; index < len; index++) {

                // If the index is in the supplied array...
                if (index in contexts) {

                    // Call the string extension function.
                    extendString();

                    // Define the context to use during the next string extension.
                    nextContext = {
                        index: index,
                        key: index,
                        value: contexts[index]
                    };

                }

            }

        // If a map list was supplied...
        } else if (contexts instanceof Map) {

            // For each entry in the supplied map...
            for (const [key, value] of contexts) {

                // Call the string extension function.
                extendString();

                // Define the context to use during the next string extension.
                nextContext = {
                    index: index,
                    key: key,
                    value: value
                };

                // Increment the counter.
                index++;

            }

        // If an iterable list was supplied (including set lists)...
        } else if (typeof contexts[Symbol.iterator] === "function") {

            // Get an iterator from the iterable.
            const iterator = contexts[Symbol.iterator]();

            // Create a variable to hold the iterator's next return.
            let next;

            // Do the following...
            do {

                // Iterate and update the variable.
                next = iterator.next();

                // If there is anything left to iterate...
                if (!next.done) {

                    // Call the string extension function.
                    extendString();

                    // Define the context to use during the next string extension.
                    nextContext = {
                        index: index,
                        key: index,
                        value: next.value
                    };

                    // Increment the counter.
                    index++;

                }

            // ... until there is nothing left to iterate.
            } while (!next.done);

        // If a list other than an array, map, or iterable was supplied...
        } else {

            // For each key in the supplied object...
            for (const key of Object.keys(contexts)) {

                // Call the string extension function.
                extendString();

                // Define the context to use during the next string extension.
                nextContext = {
                    index: index,
                    key: key,
                    value: contexts[key]
                };

                // Increment the counter.
                index++;

            }

        }

    }

    // Call the string extension a final time now that the last supplied context has been encountered.
    extendString(true);

    // Return the fully-extended string.
    return string;

});

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

@karlvr рдХреНрдпрд╛ рдЖрдк рдорд╛рдирдЪрд┐рддреНрд░ рд╕рдорд░реНрдерди рдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ рдореБрджреНрджрд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕ рдореБрджреНрджреЗ рдХреЗ рдХреБрдЫ рд╣рд┐рд╕реНрд╕реЛрдВ рдХреЛ рдкрд╣рд▓реЗ рд╣реА рд╕реБрд▓рдЭрд╛ рд▓рд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдореИрдВ рдПрдХ рд╕рд╛рдл рд╢реБрд░реБрдЖрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

рд╕рднреА 6 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

#1557 . рдХреЗ рд╕рд╛рде рдЕрдм рд╕рдВрднрд╡ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП

@nknapp рдРрд╕рд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ рдХрд┐ #1557 рдореЗрдВ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди Map рдареАрдХ рд╕реЗ рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рд╡рд░реНрддрдорд╛рди рдореЗрдВ Map рдореЗрдВ _entry_ рд╣реЛрдиреЗ рдХреЗ рдирд╛рддреЗ рдПрдХ рдкреБрдирд░рд╛рд╡реГрддреНрдд рдЖрдЗрдЯрдо рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ, рдЬреЛ [key, value] рдХрд╛ рдПрдХ рдЯрдкрд▓ рд╣реИ, рдЬрдмрдХрд┐ рдЙрдкрд░реЛрдХреНрдд рдЙрджрд╛рд╣рд░рдг рдХреЛрдб рдкреБрдирд░рд╛рд╡реГрддреНрдд рдЖрдЗрдЯрдо рдХреЛ value рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ @key рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ

рд╕рд╛рде рд╣реА, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рднрд╛рд╡ рд╡рд░реНрддрдорд╛рди рдореЗрдВ Map рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдЖрдк {{person.myMap.myMapKey}} рдирд╣реАрдВ рдХрд╣ рд╕рдХрддреЗред рдореИрдВ рдЕрдм рдЗрд╕ рдореБрджреНрджреЗ рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ рддрд▓реНрд▓реАрди рдХрд░ рд░рд╣рд╛ рд╣реВрдВред

lookupProperty рдореЗрдВ runtime.js рдореЗрдВ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдХреЗ рд╕рд╛рде рд╣рдо Map s рдореЗрдВ рдЧреБрдг рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:

    lookupProperty: function(parent, propertyName) {
      if (parent instanceof Map) {
        return parent.get(propertyName)
      }

рдХреНрдпрд╛ рдЗрд╕ рддрд░рд╣ рд╕рдорд░реНрдерди рдЬреЛрдбрд╝рдиреЗ рдХреА рдХреЛрдИ рднреВрдЦ рд╣реИ?

@karlvr рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЖрдкрдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рджреЗрдЦрдиреЗ рд▓рд╛рдпрдХ рд╣реИред рд▓реЗрдХрд┐рди рдореИрдВ рдЗрд╕ рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

@karlvr рдХреНрдпрд╛ рдЖрдк рдорд╛рдирдЪрд┐рддреНрд░ рд╕рдорд░реНрдерди рдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ рдореБрджреНрджрд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕ рдореБрджреНрджреЗ рдХреЗ рдХреБрдЫ рд╣рд┐рд╕реНрд╕реЛрдВ рдХреЛ рдкрд╣рд▓реЗ рд╣реА рд╕реБрд▓рдЭрд╛ рд▓рд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдореИрдВ рдПрдХ рд╕рд╛рдл рд╢реБрд░реБрдЖрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

@nknapp рдЖрдкрдХреА рддреНрд╡рд░рд┐рдд рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд-рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рдж; рдореИрдВрдиреЗ рдЕрднреА рд╕реБрдЭрд╛рдП рдЧрдП рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рд╕рд╛рде рдЬрдирд╕рдВрдкрд░реНрдХ рдХрд┐рдпрд╛ рд╣реИред рдХреНрдпрд╛ рд╣рдо рд╡рд╣рд╛рдВ рдЪрд░реНрдЪрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ? #1679

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

rizen picture rizen  ┬╖  6рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

novwhisky picture novwhisky  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

jlubean picture jlubean  ┬╖  8рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

LengYXin picture LengYXin  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

ShintaroOkuda picture ShintaroOkuda  ┬╖  7рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ