最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Closures - Variable Change After Use - Stack Overflow

programmeradmin3浏览0评论

I am reading about closures on MDN and I can't understand something in the following code:

var test = 1;

function makeFunc() {
  var name = 'Mozilla';
  function displayName() {
    alert(name + ' ' + test);
  }
  return displayName;
}

//Create myFunction - test should still be set to 1 at this point
var myFunc = makeFunc();

test = 99999;

myFunc();

Why is Mozilla 99999 being printed instead of Mozilla 1 when the function was created while test was assigned 1? Shouldn't primitives by value types? I also don't think assignment gets hoisted, just declaration, pretty lost.

I am reading about closures on MDN and I can't understand something in the following code:

var test = 1;

function makeFunc() {
  var name = 'Mozilla';
  function displayName() {
    alert(name + ' ' + test);
  }
  return displayName;
}

//Create myFunction - test should still be set to 1 at this point
var myFunc = makeFunc();

test = 99999;

myFunc();

Why is Mozilla 99999 being printed instead of Mozilla 1 when the function was created while test was assigned 1? Shouldn't primitives by value types? I also don't think assignment gets hoisted, just declaration, pretty lost.

Share Improve this question asked Oct 24, 2017 at 20:05 VSOVSO 12.7k28 gold badges116 silver badges201 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 4

From the article you linked:

The reason is that functions in JavaScript form closures. A closure is the bination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created.

Here, name is closed-over: It's a local variable at the time that the function was created. Though it's not a perfect analogy, you can think of it like the displayName function has an internal pointer to the stack frame containing all the local variables that were around when you defined the function. If you were to pass in name, you could see it being kept.

var test = 1;

function makeFunc(name) {
  function displayName() {
    alert(name + ' ' + test);
  }
  return displayName;
}

//Create myFunction - test should still be set to 1 at this point
var myFunc = makeFunc("one");
var myFunc2 = makeFunc("two");

test = 99999;

myFunc();   // bines closed-over name "one" with lexical scope test 99999
myFunc2();  // bines closed-over name "two" with lexical scope test 99999

Because test is in lexical scope, not a closed-over local variable, both makeFunc and makeFunc2 manipulate the same value in global scope, meaning that resetting test can manipulate the output even after you've created the closures.

A closure does not merely capture a snapshot of test when it is created, but captures the entire variable itself. This means that whenever the function myFunc is called, it will print whatever the value of test is when it was called, not the value of test when the closure was created.

In other words, inside the closure, test is still a variable, not a value. That means it can be changed and manipulated however you want, and anything that uses it will see those changes.

So for your code, as soon as you call myFunc() on the last line, the runtime will evaluate the expression name + ' ' + test, and since test is now 99999, that's what you get.

makeFunc itself returns a function which is called only after the assignment test = 9999;. The variable test is accessed from the 'outer' context (by closure).

This is because test is not updated when makeFunc() returns displayName.

Take a look at name which I removed from the method makeFunc() scope to the global scope. When makeFunc() executes, name will be updated to Mozilla from within the method scope. makeFunc() then returns the function displayName() without touching/updating test. test is only updated after the declaration of var myFunc = displayName() // return value of makeFunc().

Changing the value of test after the declaration of myFunc() will then alter the console.log() value of test.

var test = 1;
var name = "IE";

function makeFunc() {
  name = 'Mozilla';
  console.log("test inside makeFunc(): " + test);
  function displayName() {
    console.log(name + ' ' + test);
  }
  return displayName;
}

//Create myFunction - test should still be set to 1 at this point
console.log("test before myFunc declaration: " + test);
console.log("name before myFunc declaration: " + name);
var myFunc = makeFunc();
console.log("test after myFunc declaration: " + test);
console.log("name after myFunc declaration: " + name);

console.log("myFunc() before updating test");
myFunc();
test = 99999;
console.log("myFunc() after updating test");
myFunc();

发布评论

评论列表(0)

  1. 暂无评论