How do Javascript functions behave in relation to scope?

6

In Javascript, functions are objects and can be passed as a parameter to other functions. But when a function with dependencies on an object, such as variables and other functions, is passed to another object? Does it always run from the first object? What if I wanted the function to access properties of the second object? The code below prints "first object".

$(document).ready(function(){
	objeto = new Obj1();
	objeto.passa();
});

function Obj1(){
	var texto = "Primeiro Objeto";
	var minhaFunc = function(){
		document.write(texto);
	}
	var objeto = new Obj2();

	this.passa = function(){
		objeto.setFunc(minhaFunc);
		objeto.exec();
	}
}

function Obj2(){
	var texto = "Segundo Objeto";
	var minhaOutraFunc;
	
	this.setFunc = function(func){
		minhaOutraFunc = func;
	}
	
	this.exec = function(){
		minhaOutraFunc.call();
	}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    
asked by anonymous 17.01.2016 / 02:25

3 answers

9

Interesting question.

Consider the following example:

function a() {
    console.log('a', this);
}

function Obj() {
    var b = function() {
        console.log('b', this);
    }
    this.c = function() {
        console.log('c', this);
    }
    b();
    this.c();
}

function d() {
    function e() {
        console.log('e', this)
    }
    e();
}

a();
var o = new Obj();
o.c.call(window);
d();

This will give:

a Window
b Window
c Obj {}
c Window
e window

( link )

Whenever you declare a function, the execution context depends on a few factors. If the function is not owned by an object it will run with global context (cases a, b, and). When a function is a property of an object then the context of the function is that object. Functions without defined context (ie that are not property of any object) run global context.

Scope and context are different things. Scope causes b to be a private object method, ie not available outside it. The context has to do with this within that function and what it is in a given context / moment.

To change the context of a function you can use some methods:

  • .bind(novoContexto) that does not invoke function, only changes context
  • .call(novoContexto, arg1, arg2, etc) This method invokes the function
  • .apply(novoContexto, [array com argumentos]) also invokes function

Going back to your example, imagine that the scenario was this ( link ), meaning all functions and text are linked to the context

function Obj1() {
    this.texto = "Primeiro Objeto";
    this.minhaFunc = function() {
        console.log(this.texto);
    }
    var objeto = new Obj2();
    this.passa = function() {
        objeto.setFunc(this.minhaFunc);
        objeto.exec();
    }
}

function Obj2() {
    this.texto = "Segundo Objeto";
    this.setFunc = function(func) {
        this.minhaOutraFunc = func;
    }
    this.exec = function() {
        this.minhaOutraFunc();
    }
}

In this case it prints Segundo Objeto . If you move this.minhaOutraFunc(); to this.minhaOutraFunc.call(); it will undefined because you are calling / invoking the function without context. If you use this.minhaOutraFunc.call(objeto); it will give Primeiro Objeto because you define that the context is the instance of object 1 that you created within .ready() .

    
17.01.2016 / 09:56
4

This is a purely overwriting and scope issue, since in JavaScript, functions and objects can be manipulated easily as variables.

To access the method or property you only need to enter objeto.propriedade or objeto["propriedade"] .

In your example you created the object objeto when creating a variable that receives Obj2() . To access the text of Obj2() in object Obj1() , you would only need a objeto.texto .

Within an object you have to enter the this keyword when declaring fields: this.texto; and referring to the field outside the object: objeto.texto

If you want to work with inheritance, you can take a look at the methods .call() and prototype .

Your code accessing the text of Obj2() :

$(document).ready(function() {
  objeto = new Obj1();
  objeto.passa();
});

function Obj1() {
  var objeto = new Obj2();
  this.texto = "Primeiro Objeto";
  var minhaFunc = function() {
    document.write(objeto.texto);
  }
  this.passa = function() {
    objeto.setFunc(minhaFunc);
    objeto.exec();
  }
}

function Obj2() {
  this.texto = "Segundo Objeto";
  var minhaOutraFunc;
  this.setFunc = function(func) {
    minhaOutraFunc = func;
  }

  this.exec = function() {
    minhaOutraFunc.call();
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
17.01.2016 / 03:30
3

Following by parts:

First, its objeto variable in $(document).ready(... does not have var logo declared in global scope (reusable in all functions within the script), this variable will receive new Obj1() , which is a function in scope.

Inside Obj1() exists:

var minhaFunc = function(){
    document.write(texto);
}

Let's keep her quiet, we'll get back to her later.

At another point in the code of the function Obj1() , there is a new declaration of the variable objeto , but this time using var , that is, it is restricted to this function, any call to it < strong> within this function will receive, instead of Obj1() or Obj2() .

Soon after we have:

this.passa = function(){
    objeto.setFunc(minhaFunc);
    objeto.exec();
}

The function passa() , calls var objeto , which at this point refers to the function Obj2() , function which has another "subfunction" to setFunc() :

this.setFunc = function(func){
    minhaOutraFunc = func;
}

This function receives as a parameter / argument another function that will be stored in var minhaOutraFunc , knowing that it belongs to Obj2() . But in Obj1() we pass it minhaFunc() :

    objeto.setFunc(minhaFunc);

That is, var minhaOutraFunc in Obj2() now has minhaFunc() , already said previously ("we'll get back to it later"). This will print on the "First Object" screen.

But within the passar() function, there is also:

objeto.exec();

The exec() in Obj2() is a function that runs var minhaOutraFunc , remember that it has minhaFunc() that belongs to Obj1() text? Yeah. Look:

this.exec = function(){
    minhaOutraFunc.call();
}

The big problem is that the% w of% within each Obj is declared inside each constraint function, due to the use of var texto .

So when executing a function within the scope of each function, the text variable will match the function in question.

Exactly so, the text of the function var is printed on the screen.

But what if I wanted, in that case, to write the text of Obj2 ()

It suffices to declare the variable Obj1() , in the global scope, that is, without the use of texto . Look:

var objeto;
$(document).ready(function(){
	objeto = new Obj1();
	objeto.passa();
});

var texto;

function Obj1(){
	texto = "Primeiro Objeto";
	var minhaFunc = function(){
		document.write(texto);
	}
	var objeto = new Obj2();

	this.passa = function(){
		objeto.setFunc(minhaFunc);
		objeto.exec();
	}
}

function Obj2(){
	texto = "Segundo Objeto";
	var minhaOutraFunc;
	
	this.setFunc = function(func){
		minhaOutraFunc = func;
	}
	
	this.exec = function(){
		minhaOutraFunc.call();
	}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Thishappensbecausewithinthevarthelastexecutionisthefunction$(document).ready(...ofpassa().Andthelastexecutionwithinthisfunction,isthecallofwritingonthescreen,aswhatwillbewrittenisthevariableObj1()andthelastdeclarationofitwithintheglobalscope(sincethistimeitwasdeclaredwithoutthetexto)wasdoneinvar,whatisinthatfunctionwillbeprinted.

Andanotherthing,avariablehoweveryourcall/usageisnotwithObj2(),tobeconsideredglobal,shouldbedeclaredyeswithvar,butinthescopeinwhichyouwanttoreuse,globally,orinafunction.Thisalsoappliestothevarvariableatthebeginningofyourcode.

Andwhydiditworkintheprevioussituation?

Thejavascriptwilltrytogiveyouthesmallestpossibleamountoferrors,especiallywhenwetalkaboutreusingvariables.That'swhywedonothavetodetermineitstype,sowecandothingslikethis:

"5" * 8; // 40

Relevant information throughout this text: Whenever you run codes that involve variables, their execution will take into account the last statement of these variables.

    
17.01.2016 / 03:03