This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 6 years ago.
I am having problem identifying what and how is some property of "local" scope in JS. How is the property _secretNum "private" when it is clearly available outside the scope of the constructor as per below line.
document.write("Value of secretNum in secret: " + secret._secretNum
+ "<br/>");
The full code is as below,
<body>
<script type="text/javascript">
function SecretCode() {
var _secretNum = 78;
this.guessNum = function(num) {
if (num > _secretNum) {
return "Lower";
} else if (num < _secretNum) {
return "Higher";
} else {
return "You guessed it";
}
}
this.setNum = function(newNum) {
this._secretNum = newNum;
}
this.getNum = function() {
return this._secretNum;
}
}
var secret = new SecretCode();
for ( var prop in secret) {
document.write(prop + " : " + secret[prop] + "<br/>");
}
document.write("Is 70 the number: " + secret.guessNum(70) + "<br/>");
secret.setNum(9);
document.write("Value of secretNum in secret: " + secret.getNum()
+ "<br/>");
document.write("Value of secretNum in secret: " + secret._secretNum
+ "<br/>");
var secretAliter = new SecretCode();
secretAliter.setNum(17);
document.write("Value of secretNum in secretAliter : "
+ secretAliter.getNum() + "<br/>");
document.write("Value of secretNum in secretAliter : "
+ secretAliter._secretNum + "<br/>");
</script>
</body>
How is the property _secretNum "private"
It's not, I don't know where you got that code from, but it's broken.
The local variable declared by var _secretNum = 78 is private, but it's also being ignored by the setNum and getNum accessor methods. They're using this._secretNum, which is a completely different not private variable, that has nothing to do with the var _secretNum = 78 line. You can change the value of this._secretNum all you want, both directly and by using setNum, and it won't affect the variable _secretNum which guessNum uses.
The point of declaring var _secretNum as a local variable within your constructor function is that it is only accessible within that function, and by the functions that "close over" it when they are returned. Drop the this._secretNum from your accessors and just use _secretNum.
By way of example:
function MyConstructor() {
var _name = "bob" // Completely private
this._age = 45 // Not private
this.getName = function () {
return _name // public accessor for private variable
}
this.getAge = function() {
return this._age // public accessor for public property
}
}
var x = new MyConstructor();
x._name = "blah" // unrelated, ignored by getName
alert(x.getName()) // bob, not "blah"
x._age = 25 // overwrite age
alert(x.getAge()) // 25
Related
I am sure that this has been asked and answered before, but I can't seem to find the right terminology to find an answer. I need to dynamically create a series of functions for later use which use certain values defined by parameters upon creation. For example:
var i = "bar";
var addBar = function(x) {
// needs to always return x + " " + "bar"
return x + " " + i;
}
i = "baz";
var addBaz = function(x) {
// needs to always return x + " " + "baz"
return x + " " + i;
}
alert(addBar("foo")); // returns "foo baz" because i = "baz"
Is there a way I can pass i to these functions so that the original value is used, and not the reference to the variable? Thank you!
You would have to do something that stores the variable. Making a function that returns a function is one way to do it.
var i = "bar";
var addBar = (function (i) {
return function(x) {
return x + " " + i;
}
}(i));
i = "baz";
var addBaz = (function (i) {
return function(x) {
return x + " " + i;
}
}(i));
console.log(addBar("foo"));
console.log(addBaz("foo"));
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I try to define prototype functions from an array. As in the following example : my black rabbit should say 'toto' but it doesn't say it ! Why ?
function Rabbit ( type ) {
this.type = type ;
}
var funcs = ["says", "doesnt_say"];
for(var i=0;i<funcs.length;i++)
{
var f = funcs[i];
Rabbit.prototype[f] = function ( line ) {
alert(" The " + this.type + " rabbit "
+ f + " '" + line + " '") ;
};
}
var blackRabbit = new Rabbit ("black") ;
blackRabbit.says("toto");
Visible on http://jsfiddle.net/xou11bgu/
The problem is that the variable "f" is shared by all the functions you create, and it will end up having the value of the last function name.
You can use a function to construct the functions:
Rabbit.prototype[f] = function(f) {
return function ( line ) {
alert(" The " + this.type + " rabbit "
+ f + " '" + line + " '") ;
};
}(f);
This is an instance of an extremely common JavaScript stumbling block; there are many, many other similar questions here on Stackoverflow, but they're hard to find because until you know what the problem is it's hard to know what you're looking for.
You are using the variable f in the method, but that variable is shared by all methods and will contain the name of the last method.
You can use a function to create a scope where each method will gets its own variable f:
for(var i=0;i<funcs.length;i++) {
(function(f){
Rabbit.prototype[f] = function ( line ) {
alert("The " + this.type + " rabbit " + f + " '" + line + "'") ;
};
})(funcs[i]);
}
Demo: http://jsfiddle.net/xou11bgu/4/
I am getting unexpected output after setting the value of data member. What is the rationale behind this behavior?
function studentClass(id, name)
{
this.id = id;
this.name = name;
this.print = function() {
alert(id + ": " + name);
}
}
var s = new studentClass(101, "Vijay");
s.print(); // 101, Vijay
alert(s.id); // 101
alert(s.name); // Vijay
s.id = 102;
alert(s.id); // 102
s.print(); // 101, Vijay Why?
https://jsfiddle.net/00d1cvxL/5/
You should be using alert(this.id + ": " + this.name); in the print function.
Earlier it was displaying the arguments id and name that you passed to studentClass.
I was wondering how can I make it posible to get rid of putting "new" before a function, for example:
new functionToDo("thingsToDo").iGotYouBruh("Halo Humans");
is there a posible way of doing this without the "new"?
here is the code I'm trying to use without the "new":
function local (title) {
var storeTitle = title;
this.addL = function(lString) {
var storeText = lString;
localStorage.setItem(storeTitle, storeText);
console.info("Locally stored " + storeTitle.toUpperCase() + " with " + storeText.substring(0, 10) + "... As text.");
};
this.removeL = function() {
localStorage.removeItem(storeTitle);
console.info("Locally removed " + storeTitle + ".");
};
this.getL = function () {
localStorage.getItem(storeTitle);
console.info("Locally got string of " + storeTitle + ": " + localStorage.getItem(storeTitle));
};
};
and here's what I would have to do to invoke the function:
new local("storedElement").getL();
This is possible by checking whether this is an instance of the function itself and returning a new instance otherwise:
function local (title) {
if (!(this instanceof local)) {
return new local(title);
}
var storeTitle = title;
this.addL = function(lString) {
var storeText = lString;
localStorage.setItem(storeTitle, storeText);
console.info("Locally stored " + storeTitle.toUpperCase() + " with " + storeText.substring(0, 10) + "... As text.");
};
this.removeL = function() {
localStorage.removeItem(storeTitle);
console.info("Locally removed " + storeTitle + ".");
};
this.getL = function () {
localStorage.getItem(storeTitle);
console.info("Locally got string of " + storeTitle + ": " + localStorage.getItem(storeTitle));
};
};
You could use JavaScript closures. In particular look at the "Using Closures for the Module Pattern" section of this webpage for a full description. The idea is to have the function return an literal with all the required methods. Any functions or variables that you want to be kept private are just local variables for the function.
I've been programming for over 20 years, but have recently turned to JavaScript. Despite spending hours trawling the web, the penny hasn't yet dropped with the prototype inheritance method.
In the simplified code below, I am trying to inherit the 'name' property from the Synthesizer 'class' to the Roland 'class', but the only way I seem to be able to access it is by using 'Synth2.prototype.name' rather than by 'Synth2.name' (which returns undefined). I would like to get the approach working so that I can use 'Synth2.name', as portability is a design requirement.
I would be very grateful for any assistance.
function Synthesizer(name) {
this.name = name;
}
function Roland(name) {
this.prototype = new Synthesizer(name);
}
Synth1 = new Synthesizer("Analogue");
Synth2 = new Roland("Fantom G6");
document.write(Synth1.name + '<br>');
document.write(Synth2.name + '<br>');
Thanks guys! (Now updated with call to super class)...
function Synthesizer(name) {
this.name = name;
this.rendersound = function () {
document.write("applying envelope to " + this.name + "<br>");
}
}
function Roland(name) {
Synthesizer.call(this, name);
this.prototype = Synthesizer;
this.Synthesizer_rendersound = this.rendersound;
this.rendersound = function () {
document.write("applying differential interpolation to " + this.name + "<br>");
this.Synthesizer_rendersound(this);
}
}
Synth1 = new Synthesizer("Analogue");
Synth2 = new Roland("Fantom G6");
document.write(Synth1.name + '<br>');
document.write(Synth2.name + '<br>');
document.write('<br>');
Synth1.rendersound();
document.write('<br>');
Synth2.rendersound();
document.write('<br>');
document.write('Synth1.prototype ' + Synth1.prototype + '<br>');
document.write('Synth2.prototype ' + Synth2.prototype + '<br>');
document.write('<br>');
document.write('Synth1.constructor ' + Synth1.constructor + '<br>');
document.write('Synth2.constructor ' + Synth2.constructor + '<br>');
You can do this by several way.
For example :
var Synthesizer = function(name){
this.name = name;
}
function Roland(name) {
Synthesizer.call(this, name); // you call the constructor of Synthesizer
// and force Synthesizer's this to be Roland's this
}
function clone(obj){
var ret = {};
for(var i in obj){ ret[i] = obj[i]; }
return ret;
}
Roland.prototype = clone(Synthesizer.prototype); // inheritance of public functions
For Function.prototype.call : https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Call
I believe you have to set the constructor's prototype, like this:
function Synthesizer(name) {
this.name = name;
}
function Roland(name) {
this.name = name;
}
Roland.prototype = new Synthesizer();
Synth1 = new Synthesizer("Analogue");
Synth2 = new Roland("Fantom G6");
document.write(Synth1.name + '<br>');
document.write(Synth2.name + '<br>');