Trying to understand scoping within two short JavaScript functions - javascript

What is the difference between the following two JavaScript functions? I know variables declared with var are local inside the function, and if declared withthis` keyword are exposed to outer word. is there any other difference between
function student(param1, param2, param3) {
this.name = param1;
this.age = param2;
this.address = param3;
}
and
function student(param1, param2, param3) {
var name = param1;
var age = param2;
var address = param3;
}

Short answer: You would use the first one for a constructor. The second function does nothing. If you want to use 'private variables', refer to functional scoped variables in the contstructor by instance methods via a closure.
This function would be used the following way to create a student. The parameters passed in are assigned to the newly create student object.
function student(param1, param2, param3){
this.name = param1;
this.age = param2;
this.address = param3;
}
var student1 = new student('steve', 22,'333 E 3rd Ave');
var student2 = new student('rachel', 34,'111 N 1st St');
console.log(student1.name); // 'steve'
console.log(student2.name); // 'rachel'
The second one wouldn't satisfy for a constructor.
It declares variables with functional scope that remain unused. Once the execution of the student function ends, the 3 variables defined within will be garbage collected. This function doesnt seem to accomplish anything.
What do you expect this function to do? It can't be used the same way:
function student(param1, param2, param3){
var name = param1;
var age = param2;
var address = param3;
}
var badStudent = new student('Greg', 22,'222 W 2nd Rd');
console.log(badStudent.name); // undefined
Edit
Someone brought up how to make 'private member variables' using variables declared with var inside a constructor. Use closures:
function student(param1, param2, param3) {
var name = param1;
var age = param2;
var address = param3;
this.getName = function(newName) {
if (newName)
name = newName;
return name;
};
}
var myStudent = new student('steve', 22,'333 E 3rd Ave');
console.log(myStudent.name);
console.log(myStudent.getName());
console.log(myStudent.getName('dan'));
console.log(myStudent.getName());
Note that because the instance method getName refers to a functional scoped variable declared in the constructor, a closure remains that has references those variables. Because of the closure there are still references to the variables once the constructor ends, and they are not garbage collected. Thus via the instance method, you can get and set this variable which cannot be accessed via the resulting object of the constructor.

Basic difference between this. vs var variables is the scope. Variables declared as a part of this will be part of objects and variables declared with var might be private. Might because, it depends on your return. If you do not use return, then they will be private
Sample
function Student(fname, lname, dob) {
var _fname = fname,
_lname = lname,
_dob = new Date(dob);
this.fullName = _fname + " " + _lname;
this.age = (new Date()).getFullYear() - _dob.getFullYear();
}
var stu = new Student('foo', 'bar', '1998/11/13');
console.log(stu);
console.log(stu._fname)
As you see, _fname is passed and was stored using var. So its scope is till function only. So when you try to access it outside function, it is not available.
So in simple, you can use this to define public properties and use var to define private ones.

In JavaScript for creating object we use 'function' as constructor, this constructor functions basically return an object .
when you declare variable with 'var' instants of 'this.var name' , in this case mean you try using those variable to create an object .those variable declared with 'var' just are local variable inside function.
on other hand , when you use 'this.variableName' you create a property for object that constructor function try to create it .
'this.' refer to object that constructor function create.
'var variableName' is just a local variable and it is not a property of 'this' object.
function student(param1,param2,param3){
this.name=param1;
this.age=param2;
this.address=param3;
}
var t=new student('farhad',28,'address');
will create this object:
t{
name:'farhad',
age:28,
address:'address'
}
and
function student2(param1,param2,param3){
var name=param1;
var age=param2;
var address=param3;
}
var t2=new student2('farhad',28,'address');
will create this object:
t2{
}
in 't2' you don't see any property

this is used inside a function and it contains the value of the object that invokes function
Here this refers to the instance of the object & is not assigned a value until an object invokes the function where it is defined
function Student(param1, param2, param3) {
this.name = param1;
this.age = param2;
this.address = param3;
this.print = function() {
console.log(this.name + this.age + this.address)
}
}
var stud = new Student('a', 'b', 'c');
stud.print(); // abc
In the later case var name=param1;var age=param2;var address=param3; you are assigning each of the parameters to a variable and this variables have scope only inside the function

Related

How chaining of call and bind works internally?

I've a program with functions as Person, greet, specificCall and objects as kumar and chandra.
var fullName=""
function greet() {
console.log("Welcome "+ this.fullName);
}
var Person=function (name) {
this.fullName=name
console.log(this.fullName)
}
var chandra=new Person("chandrakumar")
var kumar=new Person("kumar")
var specificCall=function(){
console.log("Dude "+ this.fullName);
}
var newGreeting=Person.call.bind(specificCall)// I don't understand the meaning here
newGreeting()// logs Dude
newGreeting(kumar)//logs Dude kumar How is this happening
I think Person.call is a function as I have checked typeof Person.call and specificCall is a function again. How can I bind a function to a function?
Though I wrote this code accidentally I don't understand the logic?
Person.call fires the constructor function whereas newGreeting fires the specificCall function. if you look closely newGreeting(kumar) is equivalent to specificCall.apply(kumar). Here the not only context of the scope is changed but the whole function itself. Its like specificCall is bound to Person.call?
Call allows you to set the scope for a functions exection, defaulting to window, while activating it.
//Set global variable to fallback to
var fullname = "Window";
//Set local variable
var person = {
fullname: "Bob"
};
//Definer caller object
function logObject() {
//"this" references current scope
console.log(this.fullname);
}
//Call with nothing, defaulting to global
logObject.call();
//Call with specific object as scope
logObject.call(person);
Bind sets the scope for a function, but doesn't activate it.
//Set global variable to fallback to
var fullname = "Window";
//Set local variable
var person = {
fullname: "Bob"
};
//Definer caller object
function logObject() {
//"this" references current scope
console.log(this.fullname);
}
//Bind with nothing, defaulting to global
var logger1 = logObject.bind();
//Execute
logger1();
//bind with specific object as scope
var logger2 = logObject.bind(person);
//Execute
logger2();
As far as i can tell, you bind specificCall to a call on Person, meaning that firing newGreeting is the same as running Person.call but with specificCall as the bound scope.
It's not pretty code and i would personally recommend a more readable structure:
var fullName = "window";
var Person = function (name) {
this.fullName = name;
};
var chandra = new Person("chandrakumar");
var kumar = new Person("kumar");
function specificCall(scope) {
if (scope === void 0) { scope = window; }
console.log("Dude " + scope.fullName);
}
specificCall(); // logs Dude window
specificCall(kumar); //logs Dude kumar

"this" is different when function called from local function object

I wrote the following code, where I would expect the calls to getFull() and useGetFull() to do the same thing, since useGetFull just gets a function object for getFull() and calls it.
function Person(name, family) {
this.name = name;
this.family = family;
}
Person.prototype.getFull = function() {
console.log(this.name + " " + this.family);
};
Person.prototype.useGetFull = function() {
const f = this.getFull;
f();
// f.call(this) works as expected
}
p = new Person("Bob", "Smith");
p.getFull();
p.useGetFull();
However, they don't do the same thing, because inside useGetFull(), "this" is the global object. I noticed that using f.call(this) instead of f() works as intended, but I can't wrap my head around why I have to use it. Why is the value of "this" different depending on how/where I call the function?
A simple rule:
a.b() //b called with context a
d.e() //e called with context d
c() // c called with no context ( so the global instead)
Javascripts context depends on how the function was called.
If you haven't noticed, this.getFull() also works. This is because when you invoke the function as a property of an object (any object), that function's this will refer to that object, the object you invoked the function on, in case of foo.bar(), foo, and in case of this.getFull(), this. This is why this example works as expected:
function Person(name, family) {
this.name = name;
this.family = family;
}
Person.prototype.getFull = function() {
console.log(this.name + " " + this.family);
};
Person.prototype.useGetFull = function() {
/* getFull is preceded by something, it is invoked through "this", so
the "this" reference inside of getFull will be set to the "this" part in
the statement "this.getFull()". */
this.getFull();
}
p = new Person("Bob", "Smith");
p.getFull(); prints out Bob Smith
p.useGetFull(); // prints out Bob Smith
However, when a function is invoked not as the property on an object, in other words, when it is not accessed in a way similar to either foo.bar() or foo["bar"](), but in a way like foo(), even if foo is a reference to a variable whose value is x.y, like f() in your example, its this will be bound to the global object, in a browser, that object is window.
function Person(name, family) {
this.name = name;
this.family = family;
}
Person.prototype.getFull = function() {
console.log(this.name + " " + this.family);
};
Person.prototype.useGetFull = function() {
const f = this.getFull;
/* this call is not preceded by any objects, it is a plain
traditional function call, it is a function invokation in its
simplest form. all functions invoked in this manner will have
their "this" reference set to the global object. */
f();
}
p = new Person("Bob", "Smith");
p.getFull();
p.useGetFull();
If you are interested in this (pun not intended), go here.

Understanding this object in JS [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 6 years ago.
I am new to JS and like other novice struggling to understand concept of THIS keyword in JS. In below snippet name is changed to value1 which I understand since its c object which is calling log function .
But not able to understand why setName function is not able to change value of name variable?
var c ={
name:"value",
log:function(){
this.name="Value 1";
console.log(this.name); // c object is invoking log function hence this refers to c obj
var setName= function(newName){
this.name=newName;
}
setName('Value 2'); // isn't log function calling setName
console.log(this.name);
}
}
c.log();
Value of this is determined by how function is called.
setName is not having context of c object, it is having the global(window) context. Use Function#bind to specify that context.
var c = {
name: "value",
log: function() {
this.name = "Value 1";
console.log(this.name);
var setName = function(newName) {
this.name = newName;
}.bind(this);
setName('Value 2');
console.log(this.name);
}
};
c.log();
This line:
var setName= function(newName){
this.name=newName;
}
Will not neccessary reference the upper function, since your call to it was direct and the dunction is not a direct member of the upper function, something like: this.setName = function()....
So it will refer to a new context.
To change the upper one you have to make another reference for it not using this, like:
var upperThis = this;
var setName= function(newName){
upperThis.name=newName;
}
The function setName creates a new context, so it creates a new this.
This would do the trick:
var that = this;
var setName= function(newName){
that.name=newName;
}

Why is this instance known to the javascript function

How can it be that the sampleViewModel instance in the addChangedValue function is not undefined or null ?
From the scope of instantiation the sampleViewModel should not be known in the addChangedValue function as far my understanding is.
$(function(){
var PersonViewModel = function() {
var me = this;
me.firstName = ko.observable('Lisa'),
me.lastName = ko.observable('T'),
me.changes = ko.observableArray()
};
var sampleViewModel = new PersonViewModel();
sampleViewModel.firstName.subscribe(function(newValue) {
addChangedValue("firstname refreshed: " + newValue);
});
function addChangedValue(updatedValue) {
sampleViewModel.changes.push({ value: updatedValue });
};
ko.applyBindings(sampleViewModel, document.getElementById('data'));
});
It most certainly would. Closures are lexically-bound to the scope in which they are defined, and so anything that was defined in the scope, in which the closure was also defined, will be known to that closure.
Also, the addChangedValue will have access to any variable in its enclosing scope unless you shadow it by defining a similarly-named variable within that function.
The anonymous function that is an argument to addChangedValue forms a closure. The sampleViewModel is the same variable within the function as it is in the enclosing scope. A closure is a combination of a function (often anonymous, as in your case) with a context. All variables in scope when the function is declared are available within that function. You can read about closures here.
Yes, you've created a Closure. By example:
function init() {
var person = { name: 'Joe' };
var callMeLater = function() {
alert(person.name);
};
return callMeLater;
};
var fn = init();
fn(); // alerts 'Joe'
In this example, the init() function has its own scope - which doesn't seem to be new to you. So for example person is declared inside of it, and therefore local to init(). callMeLater is defined inside this function, creating a Closure. All variables local to the enclosing function (init) are also available to callMeLater. And that's why the last line in this example alerts Joe, and your example makes sampleViewModel available.
It is as though in Java you did this:
public class Person {
public string name;
public Person(string name) {
this.name = name;
}
public MyClosure getClosure() {
string someOtherThing = "other";
return new MyClosure(this, someOtherThing);
}
}
public class MyClosure {
public Person person;
public string someOtherThing;
public MyClosure(Person person, string someOtherThing) {
this.person = person;
this.someOtherThing = someOtherThing;
}
public void callMeLater() {
log(person.name);
}
}
var person = new Person("Joe");
var closure = person.getClosure();
closure.callMeLater(); // Logs "Joe"
You can think of the MyClosure class as being an implicit wrapper created for you by defining a function inside a function.

Setting javascript prototype function within object class declaration

Normally, I've seen prototype functions declared outside the class definition, like this:
function Container(param) {
this.member = param;
}
Container.prototype.stamp = function (string) {
return this.member + string;
}
var container1 = new Container('A');
alert(container1.member);
alert(container1.stamp('X'));
This code produces two alerts with the values "A" and "AX".
I'd like to define the prototype function INSIDE of the class definition. Is there anything wrong with doing something like this?
function Container(param) {
this.member = param;
if (!Container.prototype.stamp) {
Container.prototype.stamp = function() {
return this.member + string;
}
}
}
I was trying this so that I could access a private variable in the class. But I've discovered that if my prototype function references a private var, the value of the private var is always the value that was used when the prototype function was INITIALLY created, not the value in the object instance:
Container = function(param) {
this.member = param;
var privateVar = param;
if (!Container.prototype.stamp) {
Container.prototype.stamp = function(string) {
return privateVar + this.member + string;
}
}
}
var container1 = new Container('A');
var container2 = new Container('B');
alert(container1.stamp('X'));
alert(container2.stamp('X'));
This code produces two alerts with the values "AAX" and "ABX". I was hoping the output would be "AAX" and "BBX". I'm curious why this doesn't work, and if there is some other pattern that I could use instead.
EDIT: Note that I fully understand that for this simple example it would be best to just use a closure like this.stamp = function() {} and not use prototype at all. That's how I would do it too. But I was experimenting with using prototype to learn more about it and would like to know a few things:
When does it make sense to use prototype functions instead of closures? I've only needed to use them to extend existing objects, like Date. I've read that closures are faster.
If I need to use a prototype function for some reason, is it "OK" to define it INSIDE the class, like in my example, or should it be defined outside?
I'd like to understand why the privateVar value of each instance is not accessible to the prototype function, only the first instance's value.
When does it make sense to use prototype functions instead of closures?
Well, it's the most lightweight way to go, let's say you have a method in the prototype of certain constructor, and you create 1000 object instances, all those objects will have your method in their prototype chain, and all of them will refer to only one function object.
If you initialize that method inside the constructor, e.g. (this.method = function () {};), all of your 1000 object instances will have a function object as own property.
If I need to use a prototype function for some reason, is it "OK" to define it INSIDE the class, like in my example, or should it be defined outside?
Defining the members of a constructor's prototype inside itself, doesn't makes much sense, I'll explain you more about it and why your code doesn't works.
I'd like to understand why the privateVar value of each instance is not accessible to the prototype function, only the first instance's value.
Let's see your code:
var Container = function(param) {
this.member = param;
var privateVar = param;
if (!Container.prototype.stamp) { // <-- executed on the first call only
Container.prototype.stamp = function(string) {
return privateVar + this.member + string;
}
}
}
The key point about your code behavior is that the Container.prototype.stamp function is created on the first method invocation.
At the moment you create a function object, it stores the current enclosing scope in an internal property called [[Scope]].
This scope is later augmented when you call the function, by the identifiers (variables) declared within it using var or a FunctionDeclaration.
A list of [[Scope]] properties forms the scope chain, and when you access an identifier (like your privateVar variable), those objects are examined.
And since your function was created on the first method invocation (new Container('A')), privateVar is bound to the Scope of this first function call, and it will remain bound to it no matter how do you call the method.
Give a look to this answer, the first part is about the with statement, but in the second part I talk about how the scope chain works for functions.
Sorry for resurrecting an old question, but I wanted to add something that I recently discovered somewhere else here on SO (looking for the link, will edit/add it once I find it): found it.
I personally like the below methodology because I can visually group all my prototype and 'instance' definitions together with the function definition, while avoiding evaluating them more than once. It also provides an opportunity to do closures with your prototype methods, which can be useful for creating 'private' variables shared by different prototype methods.
var MyObject = (function () {
// Note that this variable can be closured with the 'instance' and prototype methods below
var outerScope = function(){};
// This function will ultimately be the "constructor" for your object
function MyObject() {
var privateVariable = 1; // both of these private vars are really closures specific to each instance
var privateFunction = function(){};
this.PublicProtectedFunction = function(){ };
}
// "Static" like properties/functions, not specific to each instance but not a prototype either
MyObject.Count = 0;
// Prototype declarations
MyObject.prototype.someFunction = function () { };
MyObject.prototype.someValue = 1;
return MyObject;
})();
// note we do automatic evalution of this function, which means the 'instance' and prototype definitions
// will only be evaluated/defined once. Now, everytime we do the following, we get a new instance
// as defined by the 'function MyObject' definition inside
var test = new MyObject();
You need to put the function on each specific instance instead of the prototype, like this:
Container = function(param) {
this.member = param;
var privateVar = param;
this.stamp = function(string) {
return privateVar + this.member + string;
}
}
To get the behavior you want you need to assign each individual object separate stamp() functions with unique closures:
Container = function(param) {
this.member = param;
var privateVar = param;
this.stamp = function(string) {
return privateVar + this.member + string;
}
}
When you create a single function on the prototype each object uses the same function, with the function closing over the very first Container's privateVar.
By assigning this.stamp = ... each time the constructor is called each object will get its own stamp() function. This is necessary since each stamp() needs to close over a different privateVar variable.
That is because privateVar is not a private member of the object, but part of stamp's closure. You could get the effect by always creating the function:
Container = function(param) {
this.member = param;
var privateVar = param;
this.stamp = function(string) {
return privateVar + this.member + string;
}
}
The value of privateVar is set when the function is built, so you need to create it each time.
EDIT: modified not to set the prototype.

Categories