0

I was working with dropzone and i noticed something strange:

This is my Drop:

<script type="text/javascript">

var CountFiles = 0;


$(document).ready(function () {

    Dropzone.autoDiscover = false;

    var new_file;

    const Drop1 = new Dropzone("div#myPrincipalDropzone", {
        url: "/Article/UploadFiles",

        paramName: "file",
        maxFiles: 1,
        maxFilesize: 1200,
        maxFileHeight: 840,
        maxFileWidth: 840,
        acceptedFiles: ".png,.jpg",
        addRemoveLinks: true,
        parallelUploads: 1,
        renameFile: function (file) {
            let newname = new Date().getTime() + '_';
            console.log("Nombre en RenameFile:" + newname);
            file.name = newname;
            console.log("Asigno al file el nombre:" + file.name);
            new_file = new File([file], newname + file.name);
            console.log(new_file.name);
            return new_file;
        },

        init: function (new_file) {

I noticed that my variable "new_file" at return statement has value of "123847123_Filename.ext" However when i try to call another method or function using that variable, i receive new_file as "Filename.ext" loosing my old value.

Searching on google i found that javascript have some conflicts with the name params between nested functions.

There is a way to fix this? I need to use my old value in multiple function/methods calls.

gaccerboni
  • 57
  • 7
  • 2
    Don't have `new_value` available to both but just make it local? Why do you need that anyway? – VLAZ Mar 05 '20 at 19:58
  • Don't define variables at a higher scope than they are actually needed. Never use `var` (any up-to-date linter should enforce this by default). Avoid defining complex functions inside other functions (this one may be controversial, but it tends to lead to these sorts of leaky-scope issues). – JDB Mar 05 '20 at 20:01
  • I know, but this time is required, i need to use function "renameFile" to make rename every file as "unique_id" using datetimes. Later i need to use that parameter to validate the file with the Dropozone methods just as size, or remove, etc. – gaccerboni Mar 05 '20 at 20:11
  • @JDBstillremembersMonica Never use `var` is a subjective preference, if a program runs it runs. Defining variables in higher scopes can be a stylistic preference - knowing what your variables are in a function block upfront can be less cognitive load then discovering them as you walk the routine. – Dan Kanze Mar 05 '20 at 20:11
  • 1
    @DanKanze - That line of reasoning works eqaully well for `goto`. A programmer who makes no mistakes can use `var` and `let` with equal effectiveness, but `var` scoping mistakes are an extremely [common source of avoidable errors](https://stackoverflow.com/a/11444416/211627). `let` and `const` are block-scoped, not function scoped. If you want to move your variables to the top of the block, fine, but defining them outside of their block scope also leads to a lot of potential errors. However, these are guidelines. There will always be cases where you need to deviate from "best practice". – JDB Mar 05 '20 at 20:37
  • 3
    @DanKanze "*if a program runs it runs*" [So does a burning bus](https://www.xkcd.com/1695/) – VLAZ Mar 05 '20 at 20:39
  • @VLAZ Using a burning bus as an analogy to elude to consequences from a stylistic preference is a bit dramatic and out of context when I've cited an example for my line of reasoning. – Dan Kanze Mar 05 '20 at 21:46
  • @DanKanze I find that classifying semantic differences and *real sources of bugs* as "stylistic choices" is underselling how important these are. Also, I highly disagree with declaring variables upfront *before a function* makes it clearer where they belong. `var a, b, c; function x() { a = b + c; } function y() { c--; b = a +1; }` is hardly easy to read or understand. Or a more practical examples that has had numerous posts on SO `var i; function a(x) { for (i = 0; i < x; i++) { b(i) } } function b(x) { for (i = 0; i < x; i++) { console.log(i) } }` - shared counter but usually it's implicit. – VLAZ Mar 05 '20 at 21:53
  • @JDBstillremembersMonica I think hoisting variables to reduce cognitive load or depends on the shape of the routine. It's case by case, it depends on the programmer. Like I said, it's a preference. You have to understand that `citing scoping mistakes as extremely common source of avoidable errors` is also subjective to the programmer. Some programmers don't make that type of mistake very often and so the time saved by reducing cognitive load outweighs the time spent debugging one of these errors. – Dan Kanze Mar 05 '20 at 22:09
  • @VLAZ It's case by case, it's not a blanket statement. For me, personally, `var a, b, c; function x() { a = b + c; }; function y() { a = b + c; }` is when this could make sense - under the condition they are both private functions contained by another block and are manipulating the same context but with different routines. – Dan Kanze Mar 05 '20 at 22:12
  • @DanKanze but what if that wasn't the intention? You can have the `x` and `y` functions separated by dozens if not hundreds of lines. You could easily re-use a variable *by accident* like what happens with the counter `i` many, many times. In that case your functions trample all over the variables and debugging this will be a lengthy and *very* frustrating process. Not to mention potentially very stressful if the bug isn't caught early enough and enters production. And how could you catch the bug? Even with code reviews it's very hard to spot it - consider – VLAZ Mar 05 '20 at 23:02
  • `var a, b; function x() { a = 1; b = 3; } /* different file */ var b, c; function y() { b = -7; c = 3; };` re-declaration with `var` is allowed and will not change the bindings. If both declarations are in the global scope then `b` is shared between them and the value depends on whatever last ran. Something mundane like introduce a single `setTimeout` in any of these two functions and you cannot guarantee what the value of `b` would be or if it would even make sense. By contrast having a local variable *when the intent is to have a local variable* makes perfect sense *and* avoids any problems. – VLAZ Mar 05 '20 at 23:02

1 Answers1

1

Edit 1: to correct confusion between context and scope

Edit 2: references to scope chain and removing "parameters" scope as there is no such thing

Well, the reason why it behaves like that is because of Closures

A function has access to 2 things:

  1. Local scope: variables defined inside of the function and parameters received. If defined they will be used in place of the variables available from the parent scope.
  2. Parent scope: variables defined in the scope in which the function was originally defined (often wrongly called "global" context). See Scope chains*

* The scope of a function is global to functions defined inside of it, therefore the parent's scope includes the scope of all upper parents until you reach the global scope.

Here's a snippet you can use to see a few of the many different cases that show how the context is everything when it comes to the "name" of a variable:


    const x = 'GLOBAL X VALUE';
    function A() {
      // A is referring to X within its own context
      console.log(`The value of x in A is => ${this.x}`);
      console.log(`The value of y in A is => ${this.y}`);
    }

    function B() {
      // B is referring to x within the context in which it was defined
      console.log(`The value of x in B is => ${x}`);
    }

    function C() {
      // C is referring to x within the context in which it was defined
      // That's why it also prints the value of the "global" context even if you
      // call it within a context that has a value with the same name
      console.log(`The value of x in C is => ${x}`);
    }

    function D(x) {
      console.log(`The value of x in D is => ${x}`);
      C();
    }

    function F() {
      // A is going to have access to the context of F, but it will not have access
      // to the global context
      this.y = "the other value";
      A.bind(this)();
      console.log(`The value of x in F is => ${x}`);
    }

    function G(x) {
      this.x = "HMMMM";
      console.log(`The value of local x in G is => ${this.x}`);
      console.log(`The value of param x in G is => ${x}`);
    }

    A(); // the value of x and y will be undefined
    B(); // the value of x will be the global context
    D("Parameter x value"); // the value of x will be the one passed as a parameter
    F();
    G("Parameter x value"); // the parameter and the local context are two different things

this* it's dangerous to go alone, take this documentation

  • 1
    1. There is no "parameter context" you seem to refer to the `this` keyword 2. A function has access to more than three *scopes*. Or less, depending on where it's defined. It would be the local scope, the parent, and every other parent scope until you get to the global scope. But there is only one context - `this`. – VLAZ Mar 05 '20 at 20:41
  • 1. if you run it, G will print two different values because it has a `x` that is a parameter and one that is defined in its context. 2. You are right, I think I might be skewing some of the very important binding mechanisms that javascript does when you define a function. We need more examples in order to demonstrate how that it behaves with things like => `a function defined inside of G that uses x` – Jorge Armando Palm Mar 05 '20 at 20:51
  • `x` and `this.x` have always been distinct. One is a parameter *and belongs to the scope* the other is a *property* and belongs to the context. Equating the two in any way is misleading - there is nothing common between them other than the name and even that is an accident. The mechanisms are completely different. – VLAZ Mar 05 '20 at 20:54
  • I see what you mean now, I'm referring to the scope and the context as if they were the same thing, will try to edit my answer to correct that. – Jorge Armando Palm Mar 05 '20 at 20:56
  • 1
    To further confuse things... there are scenarios where `this` is a reference to `window`, which can be populated with `var` variables where they are defined in global scope. So it *is* technically possible to have a `var x` that is later accessible as `this.x`. Yet another reason to avoid `var`. – JDB Mar 05 '20 at 21:04
  • I don't think the three "things" is correct. If you're going to enumerate the scopes, then there are *at least* two scopes - the local and the global. There might be any amount of intermediary scopes if you have `function a() { function b() { function c() {} } }` then `c` would have access to the parent (`b`) and its parent (`a`) *as well* as the local and global scopes, which makes for 4 scopes in total. To generalise, a function has access to the *scope chain* where local scope is one part of. But that means a function only has access to two "things" - the scope chain and the context. – VLAZ Mar 05 '20 at 21:18
  • Edited again to make it more correct. I think that from the context of any given function, that function doesn't know how many layers exist above it, therefore the _parent scope_ to that function is just 1 scope in addition to the _local scope_ making the list of "things" always 2 and in the case of the "global" scope the parent scope just provides you with "nothing". BUT generalizing even more because javascript is just binding the parent scope to the local scope, the function doesn't even know that it has a parent scope, making the number of "things" just *1* – Jorge Armando Palm Mar 05 '20 at 22:05
  • True - the scope chain is maintained by the environment, the function has access to it but doesn't know which binding comes from where. If you do `x += y` then each of these variables would trigger a scope chain lookup. They might be from one scope, they might be from different ones. They need not even be local. As far as the function is concerned they are either "reachable" or not. If they are found, they are used and that's pretty much it - *where* these bindings are found is irrelevant. – VLAZ Mar 05 '20 at 23:24