Why cannot use function name to retrieve property in JavaScript? - javascript

The following is the code
function add() {
var counter = 0;
this.num = 0;
function plus (){ return counter +=1;}
plus();
return counter;
}
console.log(add.num); //outputs :undefined
Function name can be treated as reference of a function object, so the num is the property of add function object, the outputs could have been 0. But the result is not like so, why?
If i change the code to:
function add() {
var counter = 0;
this.num = 0;
function plus (){ return counter +=1;}
plus();
return counter;
}
var obj = new add();
console.log(obj.num); //outputs : 0
it works correctly. Can anyone explain this? Many many many thanks.

this refers to current instance of your function. until you create a new instance using new add() this will refer to window object.
add.num will check if add has a property named num. Which is false because add refers to a function definition not an instance/object of function.
function add() {
var counter = 0;
this.num = 0;
function plus (){ return counter +=1;}
plus();
return counter;
}
console.log(add.num); //outputs :undefined because add=function(){};
while in another case, when you create object using new it returns you a javascript object having all the public properties.
///obj=Object{ num : 0};
function add() {
var counter = 0;
this.num = 0;
function plus (){ return counter +=1;}
plus();
return counter;
}
var obj = new add();
console.log(obj.num); //outputs : 0 because obj is {num:0}
Fiddle to play: http://jsfiddle.net/ZpVt9/76/

It will help to read-up on this in JavaScript: MDN
When you do new add(), the interpreter creates a new JavaScript Object/Hash and binds it to this variable in the function. So this is valid inside the scope of the function.
When you don't do a new you are calling the function without a context, so this is undefined in such cases (in 'use strict' mode).
You can explicitly pass a context to Functions using Function.apply/Function.call/Function.bind

this inside a function points to different object depending on how the function is called:
If the function is called in the global context (outside any function) this points to global object (which is window if the script is executed within a browser).
console.log(this === window) will output true.
If this is referred inside a function, then it depends if we have set strict mode.
If the code is in strict mode then this will be undefined unless we explicitly assign it to something.
If the code is not in strict mode then this will point to global object. (Which is again window if script is executed in a browser).
If function is used as constructor to make new objects then this points to the new object being made.
If function is used as object method then this points to the object method is called on.
More explanation with examples here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Every function is an object in JavaScript. But as you can see from above explanation none of the ways this points to function object itself from the same function body. Thus the only way you can set function's property is by directly assigning it to the function without using this.
There is another way of adding a property to functions. This is a very bad idea of doing so as adding any property this way will reflect in all functions used. Every function is linked to Function.prototype object. Thus adding any property in this object will get reflected in all functions.
Function.prototype.someProperty = 1;
//now try accessing it via any function object
console.log(add.someProperty); //should print 1 to console.

"num" is not a property of the "add" function is a property of the object created and returned by that function if you want to add num to your add function you need to do
add.prototype.num=0;
and remove it from your objects definition

Related

Understanding execution of properties in Javascript funciton

i am starting to learn javascript and i got confused on the execution of the properties in the javascript function.
suppose i have a funciton like this
function Counter() {
this.num = 0;
this.timer = console.log('hey');
};
now in this function, i have num and timer as a properties of the function Counter. when i try to make a instance of the function Constructor the timer property gets executed
but when i try to call the timer property explicitly, i am not getting the value / the property is not getting executed.
what is the reason behind it?
now in this function, i have num and timer as a properties of the function Counter.
No, you have num and timer properties of objects created by calling Counter as a constructor (via new, or Reflect.construct, etc.).
but when i try to call the timer property explicitly, i am not getting the value / the property is not getting executed
Just briefly on terminology (since this will help as you continue your learning), you don't "call" properties, and properties are not "executed." You "get" their value, or "access" them, or "read" them. (Or, when they're on the left-hand side of an assignment, you "set" them or "assign to" them or "write to" them.)
Your code is successfully getting the value of the timer property, which is the value that console.log('hey') returned, which is undefined.
If you meant for doing something with timer to make it run the console.log, you'd want to put it in a function:
this.timer = function() {
console.log('hey');
};
and then call it (because you do "call" functions):
d.timer();
Side note:
If that's what you meant to do, while it's perfectly fine to create functions within the constructor like that, it's slightly more common to assign them to the prototype object that new Counter will give to the objects it creates. With ES5 and earlier, you'd do that like this:
function Counter() {
this.num = 0;
} // <== No ; here, it's a declaration, not a statement
Counter.prototype.timer = function() {
console.log('hey');
};
In ES2015+, you'd probably use class syntax instead:
class Counter() {
constructor() {
this.num = 0;
}
timer() {
console.log('hey');
};
}
You use them the same way (via new).
It is quite easy.
this.timer = console.log('hey');
This line assigns to the property timer the return value of console.log('hey').
console.log prints in the console, but does not return anything, so your property stays undefined.
You are confused because you mix what is printed in the console and the actual return value.
If you just run in the console the following: console.log('hey'), you will see the following: hey then undefined. What the console.log function prints, then its return value.
On creating a new object using Counter as a constructor, a new object is created with 2 properties i.e. num and timer. num is initialized to 0 while timer is initialized with the return value of console.log() function which is undefined. This return value is stored as value of timer property and each time you get this while reading it.
If I understand correctly, you wants to add some functionality to the timer property as a function, you can do it by adding this to the prototype property of Counter so that all objects created using a constructor can inherit it.
function Counter() {
this.num = 0;
};
Counter.prototype.timer = function() {
this.timer = console.log('hey');
}
let obj = new Counter();
obj.timer();

Javascript Class properties and methods work differently

I have been working with javascript for a while and always used this notation to create objects
var className = (function() {
var property = 1; //Example of a property
var method = function () {
//Example of a method
};
});
but now I have a project where I use AngularJs and the javascript don't recognize it. I can use this one
var className = (function() {
this.property = 1; //Example of a property
this.method = function() {
//Example of a method
};
});
Is there any reason for the first one not working? In my experience I prefer the first one better
[Edit]
var className = (function() {
var property = 1; //Example of a property
var method = function () {
//Example of a method
};
})();
var className = (function() {
var property = 1; //Example of a property
var method = function () {
//Example of a method
};
});
In this example you're not actually creating anything that surmounts to a property and/or method. You're simply assigning a function to the variable className, and within that function you're creating two more variables. Variables are function-scoped, and by definition, won't be visible outside the function.
If you use AngularJS, then there are different scopes and understanding of OOP. You should probably must know $scope which is the scope for Angular objects, methods etc. Please check the documentation, also read more about Angular scopes.
In your case, you should have this code in some controller or service (factory, directive) and have something like this:
angular.module('myapp', [])
.controller('MyCtrl', ['$scope', function($scope) {
$scope.myvar = 'hello';
$scope.mymethod = function() {
console.log($scope.myvar);
};
}])
Those 2 examples do 2 very different things.
In the first, you're not actually creating any properties on the newly created object when calling className(). Anything declared using var in a function is just a locally-scoped value to that function, meaning you can't access it once you leave that function.
The second will actually create the properties property and method on the newly created object. However, when defining constructor functions it's much more common to do it like this:
function ClassName() {
this.property = 'some property value'
}
Constructor functions are typically capitalized, but this is just a style guide thing.
And then define member functions on the constructor's prototype like this:
ClassName.prototype.method = function() {
// function body where "this" refers to an instance of ClassName
}
Then you can use the constructor like this:
var someObject = new ClassName()
To understand this behavior, you need to understand how JavaScript handles scope.
The only scope within JavaScript is function scope. To understand what this means, consider the other types of scope you see in other programming languages, such as loops, classes, and if-else statements. When you create a variable within a scope, it can not be accessed outside that scope.
Because the only JavaScript scope is function scope, these two methods are functionally identical:
function myFunc(){
var x = 5; // variable declared outside loops
for(var i = 0; i < x; i++){ // iterator variable declared in loop params
var y = i; // variable declared inside a loop
for(var i = 10; i > 6; i--){
var z = i; // variable declared inside another loop
}
}
}
function myFunc(){
var x, i, y, z; // all variables declared at beginning of function
x = 5;
for(i = 0; i < x; i++){
y = i;
for(i = 10; i > 6; i--){
z = i;
}
}
}
Notice that in JavaScript, it's a logic error to use the same iterator variable in for loops in the same scope, since they will refer to the same variable (there's no "loop scope" to distinguish them).
On the other hand, function scope can be used to prevent variable names from colliding, since variables can't be accessed outside their scope.
Notice in the example below we have two different variables named x. They are different because they exist in different function scopes.
var x = "Outer Scope";
(function(){
var x = "Inner Scope";
alert(x); // output: "Inner Scope"
})();
alert(x); // output: "Outer Scope"
There's no way for the outer scope to access the value of x in the inner scope.
That brings us to the JavaScript way of creating object-like syntax.
In your first example, the variables property and method cannot be accessed outside of the "constructor" or "class definition" (or whatever you want to call the function you'll use to create objects) because they're wrapped up in a function scope. You can practically think of them as private members.
In your second example, you're using the this keyword to attach the variables as attributes of the object returned by your "constructor". The object attributes can be accessed by code outside the function scope. Think of them as public members.
If it helps put things into an object-oriented frame of reference, you can even use that syntax to provide getters and setters (accessors and mutators), like so.
var className = function() {
var property = 1;
this.getProperty = function(){return property;};
this.setProperty = function(value){property = value;};
};
var obj = new className();
obj.getProperty(); // 1
obj.setProperty(200);
obj.getProperty(); // 200
typeof(obj.property); // "undefined"
The getProperty() and setProperty() functions are able to access the property because they were defined within the same function scope; to understand this more clearly, look up "closures."
From a performance perspective, you may not want to have many functions defined in your "class definition" as above, since that results in each instance of the object having its own copy of the function (which increases the amount of memory each object requires). Instead, you can attach methods to the prototype of the function, so the methods are defined once.
className.prototype.getDouble = function(){return this.getProperty()*2;};
obj.getDouble(); // 400
A big thing to note is that prototype functions are also bound by function scope, so they can't access variables that you defined in the "class definition."
className.prototype.getTriple = function(){return property*3;};
obj.getTriple(); // ERROR: "'property' is undefined"

why does a variable need to be created in this closure

Hi I have the following closure
function createCounter() {
var numberOfCalls = 0;
return function() {
return ++numberOfCalls;
}
}
var fn = createCounter();
fn()
fn()
And I believe I understand about scope and the fact that the inner function keep the outer function's values after the outer one has returned.
What I don't understand is why I need to create this variable
var fn = createCounter()
and then invoke the variable fn() instead of initially invoking createCounter()
I saw that createCounter() just returns 'function()' instead of what has to be '1' and I don't understand why.
Thanks for the help. Read many tutorials still having problems with understanding this.
Please note: the question's isn't about how to make the code more eloquent or better, it's about understanding of what's been done
When createCounter is called it returns another function and that returned function is not evaluated unless you do so. Remember, in JavaScript functions are objects too. They can be the return value of a function.
So when you do this:
var fn = createCounter();
fn references only the function returned by createCounterfunction and not its evaluated value.
If you need to evaluate the function returned by createCounter try something like:
createCounter()();
This evaluates the returned function.
If you call it like this it will always return the same value as it creates a new numberOfCalls variable every time you call createCounter.
In Javascript, functions are objects which can be passed to and returned by other functions, as any other objects (e.g. a string, a number...).
So doing:
function foo(arg) { /* ... */ }
var someObject = new String("Hello");
foo(someObject);
is similar as:
function foo(arg) { /* ... */ }
var someFunction = new Function("Hello", "...");
foo(someFunction);
A function may thus return another function, which can be invoked as needed.
function foo() {
return new Function(...);
}
var functionReturnedByCallingFoo = foo();
functionReturnedByCallingFoo(); // can be invoked
functionReturnedByCallingFoo(); // and again
functionReturnedByCallingFoo(); // and again
Now, functions are almost never declared using the Function constructor, but rather with constructs named "function declarations" or "function expressions" - basically, the way we have defined the function "foo" in the previous examples, with a function signature and a function body delimited by curly brackets.
In such cases, the statements inside of the function body can read and write variables declared outside of the function itself ("free variables"), and not only variables declared within the function, as per the rules of lexical scoping. This is what we call a closure.
So in your case, the createCounter() function, when invoked, defines a local variable named "numberOfCalls", then return a function - the body of which having access to that variable. Executing the returned function changes the value of the variable, at each invocation, as it would for any "global" variable (i.e. variables declared in outer scopes).
Executing the createCounter() function many times would simply, each time, recreate a new local variable "numberOfCalls", initialize it to zero, and return a new function object having access to that variable.

Do, inner and outer functions get their own copy of same variable?

just a bit confused by this code
var counter = function() {
//...
var count = 0;
return function () {
return count = count + 1;
}
}
var nextValue = counter();
console.log(nextValue());
nextValue.count = 7;
console.log(nextValue());
console.log(nextValue.count);
console.log(nextValue());
Output is
1
2
7
3
It's counter intuitive. There are two representations of count. One on the outerfunction nextValue and one that only the inner anonymous function can see.
Correct, or are my missing something?
The expression nextValue.count does not refer to the local variable "count" declared inside the function. It is not possible, in fact, to create a reference to a variable local to a function from code outside the function. What you're referencing there is simply a property of the function object.
So, yes, the "count" variable that the returned function has access to is effectively completely private to that function, and it is persisted in the closure formed by the call to the "counter" function.
If you did want that to work, you could do this:
function counter() {
function actual() {
return actual.count = actual.count + 1;
}
actual.count = 0;
return actual;
}
edit — (fixed bogus code) the name "actual" inside gives the returned function safe access to the function object itself; originally I typed "this" there, and that would not work unless the external code set it up explicitly.
The way you describe it, count is effectively a private variable. When you're assign to nextValue.count, you're creating a separate property--not accessing the internal count being incremented by your counter.

javascript function object method

Hey im new to javascript and i stumbled upon this code in javascript. I dont understand how can be methods increment and print defined inside function. Does that mean that create is an object?
function create() {
var counter = 0;
return {
increment: function () {
counter++;
},
print: function () {
console.log(counter);
}
}
}
var c = create();
c.increment();
c.print(); // 1
The function "create()" returns an object. The object it returns has two properties, "increment" and "decrement", both of which have functions as values. The functions operate on the variable "counter" defined in "create()".
Each call to "create()" instantiates a new context called a "closure". The context encloses a new copy of the "counter" variable. The objects returned from calls to "create()" thus have access to their own private "counter" instance.
The keyword for you is closure.
Closures in javascript are quite covered, e.g. in How do JavaScript closures work?.

Categories

Resources