2

I have a SCOPE problem. When I declare "var text" outside the function all works. But inside the function it works only in the first part. Here is what I mean:

This is a buffer function. Executing buffer("anything") saves "anything". Executing buffer() - without the properties will return all properties.

  • buffer("Al")
  • buffer("ex")
  • buffer() <= should return Alex

But the SCOPE of "text" is wrong and it does not return the saved properties.

  function makeBuffer() {
    var text = "";
    if (arguments.length != 0) {
      for (let i = 0; i < arguments.length; i++) {
        console.log(`Adding argument - (${arguments[i]})`);
        text += arguments[i];
        console.log(`New text - (${text})`);
      }
    } else {
      console.log(`text - (${text})`);
      return text;
    }
  }
  var buffer = makeBuffer;


  buffer("One", "Two");
  document.write(buffer());

4 Answers 4

5

That is normal behaviour.

A variable defined in a given scope goes away when the scope goes away. Each call the to the function creates a new scope.

Declaring the variable outside the function is the standard way to share a value between invocations of it.

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

Comments

3

What you want is a factory:

function makeBuffer() {
  var text = "";
  
  return function buffer() {
    if (arguments.length != 0) {
      for (let i = 0; i < arguments.length; i++) {
        console.log(`Adding argument - (${arguments[i]})`);
        text += arguments[i];
        console.log(`New text - (${text})`);
      }
    } else {
      console.log(`text - (${text})`);
      return text;
    }
  }
}

var buffer = makeBuffer();

buffer("One", "Two");
document.write(buffer());

13 Comments

no need to return named function : return function buffer()
@RomanPerekhrest — If you don't return it, how do you expect to call it?
@Quentin He just means there's no need to name the function. It could be return function()
@Quentin, the final function is var buffer = makeBuffer();. That is what you are calling
It's still best practise to name it. It makes it much easier to see what is going on when you look at a stacktrace in a debugger.
|
1

You could do this using an object. This will make your code much more organized.

var Buffer = function() {
  this.text = "";
}
Buffer.prototype.append = function() {
  for (var i = 0; i < arguments.length; i++) {
    this.text += arguments[i];
  }
}
Buffer.prototype.get = function() {
  return this.text;
}

var buffer = new Buffer();
buffer.append("One", "Two");
document.write(buffer.get());

Using ES6 the syntax gets even sweeter:

class Buffer {
  constructor() {
    this.text = "";
  }
  append() {
    this.text = this.text.concat(...arguments);
  }
  get() {
    return this.text;
  }
}

var buffer = new Buffer();
buffer.append("One", "Two");
document.write(buffer.get());

2 Comments

I'm surprised that the get keyword in the ES6 implementation works as you expected. I would have guessed the interpreter would throw something like SyntaxError: Unexpected token '('
@PatrickRoberts I agree. However it's only a keyword when used in conjunction with a function name.
1

As Quentin properly pointed out in his answer, that is a normal behavior.

An alternative option to keep the value on your function without declaring the variable outside is scope is to add it as a property to the function itself.

As in JavaScript a function is a first class object, you can put such data directly into function object (like in any other objects).

An example below, please note how to get property text from your function (buffer.text).

function makeBuffer() {
  makeBuffer.text = "";
  if (arguments.length != 0) {
    for (let i = 0; i < arguments.length; i++) {
      console.log(`Adding argument - (${arguments[i]})`);
      makeBuffer.text += arguments[i];
      console.log(`New text - (${makeBuffer.text})`);
    }
  } else {
    console.log(`text - (${makeBuffer.text})`);
    return makeBuffer.text;
  }
}

var buffer = makeBuffer;

buffer("Al", "ex");
console.log(`buffer.text - (${buffer.text})`);

Alternatively consider using a closure in order to keep the value of text between function calls.

Closures are functions that refer to independent (free) variables (variables that are used locally, but defined in an enclosing scope). In other words, these functions 'remember' the environment in which they were created. More info here.

let makeBuffer = function() {
  // closure
  let text = "";
  return function() {
    if (arguments.length != 0) {
      for (let i = 0; i < arguments.length; i++) {
        console.log(`Adding argument - (${arguments[i]})`);
        text += arguments[i];
        console.log(`New text - (${text})`);
      }
    } else {
      console.log(`text - (${text})`);
      return text;
    }
  }
};
var buffer = makeBuffer();
buffer("Al", "ex");

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.