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.
Related
I am not clear about the concept of private, if I can still access it through the public method and redefine the properties of the module. I mean, I can perfectly do:
var aModule = (function() {
var privateVar = 1;
return {
publicFunction: function() {
return privateVar;
}
}
})();
aModule.publicFunction = function() {
privateVar = function() {
console.log('a new content');
}
privateVar();
};
aModule.publicFunction(); // 'a new content'
I understand that this is not possible if I write it in ES6 with let or const, because it would give me error try to overwrite the value of the private variable, but what sense does it have in ES5?
A private variable cannot be accessed or changed by code that's outside the module or class that owns the private variable.
For example, you can't do aModule.privateVar and expect it to give you anything back.
What your publicFunction is is what the Java (and other programming languages) world would call a "getter". Simply put it gives access to the value of the private variable, without allowing write access to it.
In your last example, you're not actually overwriting the private variable. You're just creating a new variable within publicFunction's scope and assigning a value to that. Just because it's also named privateVar doesn't mean it's the same area of memory.
I've added to your code to demonstrate this
var aModule = (function() {
var privateVar = 1;
return {
publicFunction: function() {
return privateVar;
},
getPrivateVar() {
return privateVar;
}
}
})();
aModule.publicFunction = function() {
privateVar = function() {
console.log('a new content');
}
privateVar();
};
aModule.publicFunction(); // 'a new content'
console.log(aModule.getPrivateVar()); //outputs 1
To give more detail on why this is, it's all about scope. privateVar exists in an anonymous function's scope. This anonymous function returns an object with several functions defined on it. When the function is called, this object is assigned to aModule, but retains access to privateVar because they share scope.
However, outside of that function we're at a different scope, which doesn't have access to the aModule's variables, except those exposed in the returned object
You are overwriting the public function and not able to access the module private variable
Consider the following new function that is created as a property of aModule that attempts to only change the value of var privateVar
The scope is different because of where it gets called and it isn't able to access that private variable
var aModule = (function() {
var privateVar = 1;
return {
publicFunction: function() {
return privateVar;
}
}
})();
aModule.newFunction = function() {
// try to change privateVar in aModule
privateVar = 3
};
aModule.newFunction();
console.log(aModule.publicFunction()); //still 1 not 3
// here's where it actually ended up
console.log(window.privateVar)
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
I have this singleton. The public functions allow to set private variables but I am not able to set them in the way that I am able to use them in the private methods:
var ServiceInterface = (function () {
// Instance stores a reference to the Singleton
var instance;
function init() {
// Singleton
// Private methods and variables
var m_action;
function performAction() {
alert(m_action);
}
return {
// Public methods and variables
callBackend: function (sAction) {
m_action = sAction;
}
};
};
})
m_action is not available throughout the public and private section of the singleton. What am I doing wrong?
I think you're referring to this
var ServiceInterface = (function () {
var m_action;
function performAction() {
alert(m_action);
}
return {
// Public methods and variables
callBackend: function (sAction) {
m_action = sAction;
performAction();
}
};
})()
ServiceInterface.callBackend("Hello world");
You need to execute anonymous function. Running it enables to create variables and functions defined with the anonymous function and these cannot be seen outside. Most of js libraries use this convention to create modules and to avoid infecting the global scope
var ServiceInterface = (function () {
// code inside
})()
These are the variables and functions confined within the scope of anonymous function executed
// var ServiceInterface = (function () {
var m_action;
function performAction() {
alert(m_action);
}
// })()
Finally, return a javascript object that will expose functions that can be accessible outside the anonymous function scope
//var ServiceInterface = (function () {
// var m_action;
//
// function performAction() {
// alert(m_action);
// }
return {
// Public methods and variables
callBackend: function (sAction) {
m_action = sAction;
performAction();
}
};
//})()
However, why go through the trouble of making private variable and method for a singleton?
This is how you create a singleton with a private member variable.
ServiceInterface = new (function() {
var m_action = false;
this.setAction = function(s) {
m_action = s;
};
this.getAction = function() {
return m_action;
};
this.performAction = function() {
alert(ServiceInterface.getAction());
};
this.createCallback = function() {
return function(sAction) {
ServiceInterface.setAction(sAction);
};
}
})();
ServiceInterface.setAction("secret");
ServiceInterface.performAction();
ServiceInterface becomes a singleton because the constructor function is thrown away after it's created. ServiceInterface = new (.....)(); is how it's executed right after being declared. It's a singleton because there is no way for someone to create another instance.
I don't use var to create the instance. When you exclude var and you're not inside a function the new variable will be attached to the prototype of the parent object. In the browser this will be window. window is like a global singleton in javascript.
The local variable m_action is persisted because setAction and getAction reference it as closure functions, and the variable is attached to their scope. So they can be used as setter/getter methods.
You can now use ServiceInterface.setAction(sAction); in your callbacks to set the private member.
http://jsfiddle.net/thinkingmedia/w7DdE/6/
I have JavaScript code as below;
var foo = (function() {
//Private vars
var a = 1;
return {
//Public vars/methods
a: a,
changeVar: function () {
a = 2;
}
}
})();
Now I am not sure how the syntax for public vars/methods works ?
Could you please corelate how just "returning" the vars/methods makes them as public ?
Thank you.
The value of the variable foo is actually the value returned by this function. Notice on the last line, the (), indicating that this function is evaluated immediately. By evaluating a function and assigning its return value to a variable, you are able to hide variables inside a local (function) scope, such that they are not accessible outside that scope. Only members on the returned object are accessible, but because any functions inside form a closure with their outer scope, you can still use local (hidden) variables.
An example of this would be to hide some local state and only allow access to it through a method:
var foo = (function() {
//Private vars
var a = 1;
return {
//Public methods
getVar: function () {
return a;
},
setVar: function (val) {
a = val;
}
}
})();
Okay, you've returned an object in the anonymous function, which means that the object is assigned to foo. So you can access the object's properties like foo.a or foo.changeVar, but you can continue to let the private variables exist, within the function's scope. Can't help much without a more specific question.
Is there a way to create private global variables in JavaScript? I have tried looking around, and I keep bumping into talk of constructors - which don't seem too global.
Thanks
Not sure what your use case is. I'll assume you have a js script file containing some functions and variables and you want to expose some of those globally, but keep the rest private to your script file. You can achieve this with a closure. Basically you create a function that you execute immediately. Inside the function you place your original code. You then export the functions you need into the global scope.
// Define a function, evaluate it inside of parenthesis
// and execute immediately.
(function(export) {
var myPrivateVariable = 10;
function myPrivateFunction(param) {
return param + myPrivateVariable;
}
export.myGlobalFunction = function(someNumber) {
return myPrivateFunction(someNumber);
};
})(this); // The *this* keyword points to *window* which
// is *the* global scope (global object) in a web browser
// Here it is a parameter - the *export* variable inside the function.
// This is executed in the global scope
myGlobalFunction(2); // yields 12 (i.e. 2 + 10)
myPrivateVariable; // Error, doesn't exist in the global scope
myPrivateFunction(2) // Error, doesn't exist in the global scope
To answer your question, no, that is not possible as there are no access modifiers in javascript. A variable declared in global scope is accessible to any function.
As pointed out in the comments to this answer, you can create objects which have private members. Crockford has a page on private members in Javascript. He uses the following code to illustrate his point:
function Container(param) {
// private method
function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}
this.member = param;
var secret = 3;
var that = this;
// privileged method
this.service = function () {
return dec() ? that.member : null;
};
}
In the above example, param, secret, and that are all private in that they are not accessible from the outside. To be more clear, these variables can only be accessed by privileged or private methods, the difference being that privileged methods can be called from any instance of the object. As is suggested in the comments, this is achievable by using closures.
Quoting from Crockford for a quick explanation on closures, but you can find plenty of related questions.
What this means is that an inner function always has access to the
vars and parameters of its outer function, even after the outer
function has returned.
in order to have private members. you need to use closures.
following code help you understanding the concept.
function CustomArray () {
this.array = [];
var privateData = 'default data';
this.getPrivateData = function () {
return privateData;
};
this.setPrivateData = function (data) {
privateData = data;
};
};
CustomArray.prototype.push = function (data) {
this.array.push(data);
};
CustomArray.prototype.unshift = function (data) {
this.array.unshift(data);
};
CustomArray.prototype.pop = function () {
this.array.pop();
};
CustomArray.prototype.shift = function () {
this.array.shift();
};
CustomArray.prototype.print = function () {
console.log(this.array.join(','));
};
var array = new CustomArray();
array.push(10);
array.push(20);
array.push(30);
array.push(5);
array.unshift(3);
array.unshift(2);
array.unshift(1);
array.unshift(0);
array.pop();
array.shift();
array.print();
console.log(array.getPrivateData());// default data
array.setPrivateData('am new private data');
console.log(array.getPrivateData());//am new private data