简体   繁体   中英

Apply a function to several elements at once

When I apply the same function to several elements, I usually do the following:

var func = function(elem) {
  elem.style.color = 'red';
};

var p = document.querySelector('p');
var div = document.querySelector('div');

func(p);
func(div);

I was wondering if there is an easy way to apply this function to two (or more) elements at once ? Eg :

func(p, div); // Apply my function to both elements at once

You can make use of arguments :

var func = function() {
    var args = [].slice.apply(arguments);

    args.forEach(function (elem) {
        elem.style.color = 'red';
    });
};

Call it like you wanted:

func(p, div);

On a side note, there is a functionality called "rest parameter" planned in ECMAScript 6 that allows for just what you had in mind, take a look here .

Transforming the function so it returns itself

By transforming the function so it returns itself, you can use the syntax

func(p)(div)

To make this work, you'll need to arrange for func to return itself.

function selfify(fn) {
    return function self() {
        fn.apply(this, arguments);
        return self;
    };
}

Then

funcx = selfify(func);
funcx(p)(div);

Transforming the function so it is called on each argument

If you would prefer the func(p, div) syntax, write the following kind of transformer, which creates a function which calls an underlying function on each of its arguments:

function repeatify(fn) {
    return function() {
        Array.prototype.forEach.call(arguments, fn, this);
    };
}

Then

funcy = repeatify(func);
funcy(p, div);

This obviously won't work well if the underlying function takes two or more parameters.

In ES6, using rest parameters, the above can be written somewhat more simply as

function repeatify(fn) {
    return function(...args) {
        [...args].forEach(fn, this);
    };
}

Real simple solution

If all the above functional-style programming is too much to wrap your head around, all you really need to do is:

[p, div].forEach(func);

You could combine some of the great answers here to come up with a functionnal programming code easily reusable :

var f = function (applyTo) {
    var makeArray = function(arrayLike) {
        return Array.prototype.slice.call(arrayLike);
    };
    return function () {
        var args = makeArray(arguments),
            elements = [];
        args.forEach(function (selector) {
            var newElements = makeArray(document.querySelectorAll(selector));
            console.log(newElements);
            elements = elements.concat(newElements);
        });
        elements.forEach(applyTo);
    }
};

var redify = function (elem) {
    elem.style.color = '#F00';
}

var underline = function (elem) {
    elem.style.textDecoration = 'underline';
}

var overline = function (elem) {
    elem.style.textDecoration = 'overline';
}

f(redify)('div', 'p');

f(underline)('div.test2');

f(overline)('p.test2');

JSFiddle

var forEach = Array.prototype.forEach;
var elms = document.querySelectorAll('p, div'); // css selector to match both p & div
var func = function(elem) {
    elem.style.color = 'red';
};

forEach.call(elms, func);

Consider combining a basic loop from the previous answers and the use of classes instead of querySelector.

Thus you could assign the needed classed to all your element that you'll need to pass through the function and then just call the function with them:

var func = function (elem) {
    for (var i = 0; i < elem.length; i++) {
        elem[i].style.color = 'red';
    }
};

func(document.getElementsByClassName("yourClass"));

The right way to do is through the use of classes.

<p class="myClass"></p>
<div class="myClass"></div>

Then in your javascript when you wish to change the color of these two elements, simply do:

var elems = document.getElementsByClassName("myClass");

for(var i=0; i<elems.length; i++){
    func(elem[i]);
}

It'll be useful for long run when you have large number of elements, organizing them in classes based on your needs is the way to go.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM