Why does changing font size with an event through javascript require closures?

落爺英雄遲暮 提交于 2020-01-05 12:14:28

问题


I've been reading the mozdev article on closures and it has this fiddle example:

function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}

the idea is to call makeSizer with a size, from an on-click event and it changes the font size. But if you cut out the nameless function and just do this:

function makeSizer(size) {
    document.body.style.fontSize = size + 'px';
}

the clickable links stop having any effect and font size goes directly to the largest, as if the size16 link was clicked and the links don't have an on-click event anymore. Adding return doesn't change the behaviour.

(if it's unclear what I'm talking about, click the links above the examples, they have the fiddles)

My question is, why does this need closures/callbacks? Shouldn't a simple statement work? If it's about making a call to a function, why doesn't it work after the script loads? I get why it would default to the last size, since the function call now directly alters the size (and size16 is called last), instead of waiting for the call, but still, why doesn't it work after the page loads?


回答1:


To answer your question: Changing the font-size does not require closures.

Now to why removing the inner function does not work:

makeSizer is not the event handler. It is a function that creates functions and returns them. These functions are the event handlers. Let's break it down a bit:

var size12 = makeSizer(12);
document.getElementById("size-12").onclick = size12;

The first line executes the function makeSizer with 12 as a parameter. It creates another nameless function that sets the body's font-size to 12 and returns it. That means, that the variable size12 now holds the function that has been created by makeSizer. size12 does not hold the function makeSizer itself.

In the second line you assign size12 to the onclick-Event of the clickable element. So the event handler for this event is now the function that sets the font-size to 12. It does not execute the function makeSizer!

If you change the function makeSizer so that there is no inner function anymore, it does not return anything, hence the variable size12 is "empty". Then, when you assign size12 the the onclick-Event, you assign "nothing" to the onclick-Event. That is why nothing happens.




回答2:


What is happening without the callback is that the size is being set in quick succession to 12 then 14 then 16 as the script loads.

The callback is needed because you are defining what will happen when the link is clicked.

To understand the version with makeSizer, you should first understand the following version, which should do the same thing:

var setSize12 = function() {  document.body.style.fontSize = '12px'; };
var setSize14 = function() {  document.body.style.fontSize = '14px'; };
var setSize16 = function() {  document.body.style.fontSize = '16px'; };

document.getElementById('size-12').onclick = setSize12;
document.getElementById('size-14').onclick = setSize14;
document.getElementById('size-16').onclick = setSize16;



回答3:


The value you assign to onclick needs to be a function that will get called by the browser with the click event as an argument. You want your function to be called with the size parameter. That won't work.

The solution is to find a way to bind the size into the function passed to the onclick and for that you use closures.

If you look closely at the mozdev code, you will see that as onclick handler they assign a function that doesn't expect any parameters:

function(){ document.body.style.fontSize = size + 'px'; }

That function does indeed use the size variable, but it is not defined in its scope. Instead, they create a closure over the function where the size variable is defined. To this closure they pass the parameter that you wish to give:

function makeSizer(size) {
  // size is defined here, because it is a parameter
  return function() {
    // same size is here
    document.body.style.fontSize = size + 'px';
  };
}

The return value of makeSizer('12px') is the function above that changes fontSize with no parameters and the size variable bound to '12px'.




回答4:


In the non-working example, as soon as you define the variable

var size12 = makeSizer(12);

you are calling makeSizer(12) which executes the function and changes the size.

By contrast, on the working example, when you define the variable

var size12 = makeSizer(12);

you are creating a function (that's what makeSixer() returns in this case) with the parameter 12 but since you're just returning the function you aren't executing it.




回答5:


Because the onclick event requires a function. So when you just return document.body.style.fontSize = size + 'px';, it doesn't get executed.




回答6:


Since your toggling the font size on the click event you need to assign a function to act as the event handler when the click event is performed.

In the code example, the functions are stored into variables, being assigned the return value of the makeSizer function.

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

This requires makeSizer to retain the value of the supplied argument so it can be referenced when the event is actually fired. Closures are a mechanism used to retain the scope of an outer function when calling an inner function. In this case that inner function is stored in the variables you have declared and which are called onclick of each respective anchor tag. Those closures contain the size argument supplied when the function was declared thanks to the closure.

Honestly, I think this is just a poor example. If I were setting the font-size via Javascript, I would simply use an anonymous function:

document.getElementById("something").onclick = function(){
   document.body.style.fontSize = '16px';
};

or with the function:

document.getElementById("something").onclick = function(){
   makeSizer(12);
};


来源:https://stackoverflow.com/questions/19134072/why-does-changing-font-size-with-an-event-through-javascript-require-closures

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!