Javascript dynamically created functions in an object - javascript

I'm just studying javascript and I faced an issue related to scoping.
Here's the code
function User (properties) {
for (var i in properties) {
(function () {
this ['get' + i] = function () {
return properties [i];
};
}) ();
}
}
var me = new User ({
Id : 54,
Name : 'ohyou'
});
console.log (me.getName ());
console.log (me.getId ());
How I want it to work: it should create two functions getName and getId that belong to the me object.
How it works: it creates two functions just as I want, but they belong to the window
What I tried:
I tried removing the function on the line 3. It does what I want, but now it returns the name "ohyou" two times, instead of returning the id and the name
I tried using the functions from the window scope, the problem as in the previous case persists - it returns the name twice.
The question: what am I doing wrong and how do I make it work as I want?
P.S. Making this post using phone, sorry for possible typos or formatting issues. Also, please forgive me my english skills.

Try to understand why the following code works:
function User(properties) {
for (var i in properties) {
with ({ i: i, self: this, props: properties }) {
self["get" + i] = function () {
return props[i];
};
}
}
}
var me = new User({
Id: 54,
Name: "ohyou"
});
alert(me.getName());
alert(me.getId());
This is an example of one of the legitimate uses of the with statement.
I find the with statement to be more succinct than using an immediately invoked function expression (IIFE) as others are suggesting.
Edit: The with keyword is not bad if you use it correctly. There are some legitimate uses of with:
http://webreflection.blogspot.in/2009/12/with-worlds-most-misunderstood.html
The reason your code doesn't work is because every function has it's own value of this. Hence when you immediately invoke the function expression within the for loop, the value of this inside the function is no longer your new object. It is window. To solve that problem you could do something like:
(function (i, self, props) {
self["get" + i] = function () {
return props[i];
};
}(i, this, properties))
However using the with statement is clean and faster. It's faster because you're not calling a function.

function User (properties) {
var that = this;
for (var i in properties) {
(function (i) {
that ['get' + i] = function () {
return properties [i];
};
}) (i);
}
}
var me = new User ({
Id : 54,
Name : 'ohyou'
});

You can avoid all these closures and other things if you use Object.keys and then forEach, which already introduces a new scope. Then you'd have to pass the this value, which is the second parameter:
function User(properties) {
Object.keys(properties).forEach(function(k) {
this['get'+ k] = function() {
return properties[k]
}
},this)
}

One thing you must remember, any function that does not belong to any object, will always belong to window object.
For example if we modify your object and add a new method,
me.doSomeWork = function(){
this.myLuckyNumber = 10;
var that = this;
function doubleMyLuckyNumber(){
console.log(this); //window
that.myLuckyNumber = that.myLuckyNumber * 2;
}
doubleMyLuckyNumber();
};
me.doSomeWork();
console.log(me.myLuckyNumber) //outputs 20
So always save the reference to a var to use it in inner methods. You can use any of the way that others suggested but I prefer James emanon's approach.

Related

Privileged Methods - how to get values of properties that are passed to the function?

(example is from the book but I don't seem to get it)
function User (properties){
for( var i in properties){
(function(){
this["get"+i] = function () { return properties[i];};
this["set"+i] = function (valueOne) { properties[i] = valueOne; };
}) ();
}// END for
}// END User
var userOne = new User ({ name: "Billy", age: 35 });
userOne.getname();
When I run this, User does not have getname method. How can I make the privileged method works?
You need both this and i captured in the closure:
function User (properties){
for( var i in properties){
(function(t, i){
t["get"+i] = function () { return properties[i];};
t["set"+i] = function (valueOne) { properties[i] = valueOne; };
}) (this, i);
}// END for
}// END User
this is not who you think it is. Since you invoked the IIFE on nothing, this will be the global scope, so the window will get the methods getname, etc, which is not what you expected.
To fix it, if you want to keep the IIFE, you need to call it on the right context:
function User (properties){
for( var i in properties){
(function(key){
this["get"+key] = function () { return properties[key];};
this["set"+key] = function (valueOne) { properties[key] = valueOne; };
}).call(this, i);
}// END for
}// END User
var userOne = new User ({ name: "Billy", age: 35 });
userOne.getname();
Note that you also forgot to pass the i argument to the function and to interpret it as parameter. Otherwise all the functions would get bound to the same key, thus userOne.getname would return 35.
This is because you used an immediately invoked function
for( var i in properties){
(function(){ //<--- This
this["get"+i] = function () { return properties[i];};
this["set"+i] = function (valueOne) { properties[i] = valueOne; };
}) ();
}
Remove it and it will still not work, but your methods will be there. To get it fully working you should preserve i
for( var i in properties){
(function(i){ //<--- This
this["get"+i] = function () { return properties[i];};
this["set"+i] = function (valueOne) { properties[i] = valueOne; };
}) (i); //<--- and this
}
The latter issue is not as interesting (though related to) the first one.
Javascript has only what is known as "function scope" meaning that the only thing that limits function scope is...well...a function. Therefore, a common pattern is to use IIFEs like this inside of for loops or in many places where you don't want variables to leak.
However, the this parameter in javascript is weird. Understand the following and it will save you a ton of hassle: this in javascript is no different from any other parameter.
Let me explain.
There are four ways to invoke a function in javascript.
myFn.call("this param", "param 1", "param 2"); //this is "this param"
myFn.apply("this param", ["param 1", "param 2"]); //this is "this param"
myFn("param 1", "param 2");
//javascript takes a guess at what `this` should be -
//usually it is set to the global `window`.
new myFn("param 1", "param 2");
//`this` is a new function with its' prototype set to myFn.prototype
If you were always to use the .call form all ambiguity would be gone and you can see that this is exactly like every other parameter. However that's extra syntax and people prefer using the simpler form which means you have to consider the rules for what is "this".
Therefore what you are doing in your example is placing getters and setters on the global window object.
I'm going to make a statement here that your book probably doesn't agree with but that I've picked up from years of learning, working with, and teaching javascript:
Don't use the new and this keywords.
These two keywords introduce a ton of concepts into JS that are confusing and really - unless you're making something very performance sensitive (you're not, I know you think you are, but you're not) - not necessary. Instead create new objects simply like this:
var user = { name: "Billy", age: 35 };
if you absolutely must have getters and setters this will do it:
function createObjectWithProps (properties){
var obj = {};
var state = {}[
for( var k in properties){
(function(key) {
obj["get"+key] = function () { return state[key];};
obj["set"+key] = function (valueOne) { state[key] = valueOne; };
})(k)
}
return obj;
}
var userOne = createObjectWithProps ({ name: "Billy", age: 35 });
userOne.getname();
Although I'll go even further to state that getters and setters are not terribly useful in js, and when you DO use them it is standard to follow a pattern similar to what knockout does.
The problem is the "this" keyword.
Because you are using it inside an immediately invoked function it is pointing to the global scope.
try this:
function User (properties){
for( var i in properties){
(function(self,i){
self["get"+i] = function () { return properties[i];};
self["set"+i] = function (valueOne) { properties[i] = valueOne; };
}) (this,i);
}// END for
}// END User

Javascript classes and variable references

I'm trying to solve this puzzle minded Javascript OOP problem.
So I have the following class :
var ClassA = function() {
this.initialize();
}
ClassA.prototype = {
methods : ['alpha','beta','gama'],
initialize : function() {
for ( var i in this.methods ) {
this[this.methods[i]] = function() {
console.log(this.methods[i]);
}
}
}
}
var a = new ClassA();
When I call every method I expect to print the name of it, right? But here is what i get :
a.alpha(); // returns gama ?!?
a.beta(); // returns gama ?!?
a.gama(); // returns gama
But when my class looks like this :
var ClassB = function() {
this.initialize();
}
ClassB.prototype = {
methods : ['alpha', 'beta', 'gama'],
initialize: function() {
for ( var i in this.methods ) {
this.addMethod(this.methods[i]);
}
},
addMethod: function(method) {
this[method] = function() {
console.log(method);
}
}
}
var b = new ClassB();
b.alpha(); // returns alpha
b.beta(); // returns beta
b.gama(); // returns gama
Why is this happening ?
for ( var i in this.methods ) {
this[this.methods[i]] = function() {
console.log(this.methods[i]);
}
}
Your problem lies here. When this loop ends, i is the last element. Each function uses the same i, so they are all the last element.
When you use addMethod you are making a closure to "capture" the correct value.
EDIT: When you call addMethod you are "copying" the value, instead of using the i value, which changes with each loop iteration.
In your first version:
initialize : function() {
for ( var i in this.methods ) {
this[this.methods[i]] = function() {
console.log(this.methods[i]);
}
}
}
The methods that you create within initialize all refer to the same i variable from initialize - and after initialize runs i has the value "gama", so regardless of which of the methods you call that's the value of i that they'll log to the console. JS doesn't store the current value of i at the time the method is created.
JS creates a "closure" for each function - variables declared in your initialize function (i.e., i) continue to be in scope for the nested function(s) even after initialize has finished.
The second version calls addMethod to add each method:
addMethod: function(method) {
this[method] = function() {
console.log(method);
}
}
...and so when they run they'll refer to their own "copy" of the method parameter because then there is a separate closure for each of the methods.
Edit: See also this question: How do JavaScript closures work? (several answers there explain this more clearly than I did).
You can fix your first example by adding an anonymous closure:
initialize : function() {
for ( var i in this.methods ) {
(function (i) { // anonymous closure
this[this.methods[i]] = function() {
console.log(this.methods[i]);
}
}).call(this, i); // use .call() if you need "this" inside
}
}
Now it will work the same way as your second example. "Anonymous" means that the closure is made by function which doesn't have a name and is called instantly as it is "created".
Note sideways: use .call(this, ...) to preserve this inside the called function, or you can do var that = this, use that instead of this and call the function normally:
for ( var i in this.methods ) {
var that = this;
(function (i) { // anonymous closure
that[that.methods[i]] = function() {
console.log(that.methods[i]);
}
})(i); // Called normally so use "that" instead of "this"!
}
Well, first of all stop using for (property in object) loops on Arrays. It's all fun and games until somebody prototypes to the Array object which is both a perfectly reasonable and very useful/popular thing to do. This will result in custom methods getting added to your for x in array loops.
As for the problem, it's doing exactly what you told it to do in version 1. The problem is that by the time you get around to firing it, i is the last thing i was, 'gamma'. When you pass a reference into a function as an argument, the function holds on to the value's state as it was passed.

How to break closures in JavaScript

Is there any way to break a closure easily in JavaScript? The closest I have gotten is this:
var src = 3;
function foo () {
return function () {
return src; }
}
function bar (func) {
var src = 9;
return eval('('+func.toString()+')')(); // This line
}
alert(bar(foo()));
This prints '9', instead of '3', as a closure would dictate. However, this approach seems kind of ugly to me, are there any better ways?
Your code is not breaking the closure, you're just taking the code the makes up a function and evaluating it in a different context (where the identifier src has a different value). It has nothing at all to do with the closure that you've created over the original src.
It is impossible to inspect data that has been captured in a closure. In a sense, such data are even more "private" than private members in Java, C++, C# etc where you can always use reflection or pointer magic to access them anyway.
This could be useful if you are trying to create multiple similar methods in a loop. For example, if you're creating a click handler in a loop that relies on a loop variable to do something a little different in each handler. (I've removed the "eval" because it is unnecessary, and should generally never be used).
// Assign initial value
var src = 3;
// This is the regular js closure. Variables are saved by reference. So, changing the later will
// change the internal value.
var byref = function() {
return src;
}
// To "break" the closure or freeze the external value the external function is create and executed
// immidiatly. It is used like a constructor function which freezes the value of "src".
var byval = function(s) {
return function() { return s };
}(src);
src = 9;
alert("byref: " + byref()); // output: 9
alert("byval: " + byval()); // output: 3
As others said this doesn't seem to be the right thing to do. You should explain why you want this and what you want to achieve.
Anyway, one possible approach could be to access properties of an object inside your function. Example:
var src = 3;
function foo (context) {
context = context || window; // Fall back to the global namespace as default context
return function () {
return context.src;
}
}
function bar (func) {
var context = {src: 9};
return func(context);
}
alert(bar(foo));
If you want to access a variable in a wider scope, just don't reuse the variable name in a narrower scope.
That's how it is supposed to work. Work with it instead of trying to fight it.
Here is the code see if you can understand , closures defined within a loop .
var clicked = false;
for(var i=0;i<temp.length;i++){
(function(index){
if(clicked) return false;
$(temp[index]).on('click',function(){
if($(temp[index]).text()=="" && !$(".cell1").val()){
$(this).text(player1Val);
$(".cell1").val(true);
console.log("first player clicked ");
clicked = true;
$(this).off();
for(var j=0;j<temp.length;j++){
$(temp[j]).off('click');
}
return false;
}
else return false;
});
})(i);
}

Scoping problem with Javascript callback

I am having some trouble getting a callback function to work. Here is my code:
SomeObject.prototype.refreshData = function()
{
var read_obj = new SomeAjaxCall("read_some_data", { }, this.readSuccess, this.readFail);
}
SomeObject.prototype.readSuccess = function(response)
{
this.data = response;
this.someList = [];
for (var i = 0; i < this.data.length; i++)
{
var systemData = this.data[i];
var system = new SomeSystem(systemData);
this.someList.push(system);
}
this.refreshList();
}
Basically SomeAjaxCall is making an ajax request for data. If it works we use the callback 'this.readSuccess' and if it fails 'this.readFail'.
I have figured out that 'this' in the SomeObject.readSuccess is the global this (aka the window object) because my callbacks are being called as functions and not member methods. My understanding is that I need to use closures to keep the 'this' around, however, I have not been able to get this to work.
If someone is able show me what I should be doing I would appreciate it greatly. I am still wrapping my head around how closures work and specifically how they would work in this situation.
Thanks!
Well the most straightforward thing to do is to just wrap "this.readSuccess" in another function:
SomeObject.prototype.refreshData = function()
{
var obj = this;
var read_obj = new SomeAjaxCall("read_some_data", { },
function() { obj.readSuccess(); }, function() { obj.readFail(); });
}
Some Javascript frameworks provide a utility to "bind" a function to an object, which simply means that it creates one of those little functions for you. Note that the variable "obj" will be "remembered" by those little functions, so when your handlers are called the "this" reference will be to the object that was used to call "refreshData".
Your problem here is not exactly a closure or scoping problem. The problem is that when you assign this.readSuccess to a variable, you assign the function itself without any notion of the object it originaly belongs to.
In the same way, you can take a regular, "stand-alone" function and use it as method of an object:
function hello() {
alert("Hello "+this.planet);
}
var planet = "Earth";
hello(); // -> 'Hello Earth'
var Venus = {
planet: "Venus"
};
hello.apply(Venus); // -> 'Hello Venus'
Venus.hello = hello;
Venus.hello(); // -> 'Hello Venus'
And your problem can be replicated in this example
var helloVenus = Venus.hello;
helloVenus(); // -> 'Hello Earth'
So your problem is to assign this.readSuccess to some variable and having it called as a method of this. Which can be done with a closure as demonstrated by Pointy. Since I don't know what "SomeAjaxCall" actually does, it's hard to know if the value of this is actually lost and if var obj = this is actually needed. Chances are that it's not, so you can be fine with this kind of code:
var helloVenus = function() { Venus.hello() }
helloVenus(); // -> 'Hello Venus'
In your case, that would be (edit: adding the arguments passed to the handler) :
SomeObject.prototype.refreshData = function()
{
var read_obj = new SomeAjaxCall(
"read_some_data",
{ },
function () { this.readSuccess.apply(this, arguments) },
function () { this.readFail.apply(this, arguments) }
);
}
As noted previously, several js frameworks offer a bind function to simplify this kind of issue. But you don't need a complete framework just for this : here is a perfectly fine Function#bind method that works an plain javascript:
Function.prototype.bind = function(obj) {
var __method = this;
var args = [];
for(var i=1; i<arguments.length; i++)
args.push(arguments[i]);
return function() {
var args2 = [];
for(var i=0; i<arguments.length; i++)
args2.push(arguments[i]);
return __method.apply(obj, args.concat(args2));
};
}
With the help of Function#bind, you can write:
SomeObject.prototype.refreshData = function()
{
var read_obj = new SomeAjaxCall(
"read_some_data",
{ },
this.readSuccess.bind(this),
this.readFail.bind(this)
);
}
The following site seems to suggest that the problem may be more in your "class" building than in the usage. If you read down to the "rewrite using prototype properties", they write that that particular method of "class" structuring will keep the methods global instead of instance-based. Perhaps another creation method?
http://devedge-temp.mozilla.org/viewsource/2001/oop-javascript/

JavaScript function declaration

Are the JavaScript code snippets given below some sort of function declaration? If not can someone please give an overview of what they are?
some_func = function(value) {
// some code here
}
and
show:function(value){
// some code here
}
There are six ways/contexts in which to create functions:
1) Standard declarative notation (most familiar to people with C background)
function foo() {}
All the rest are function expressions:
2) As a method of an object literal
var obj = {
foo: function() {}
};
3) As a method of an instantiated object (created each time new is exectued)
var Obj = function() {
this.foo = function() {};
};
4) As a method of a prototype (created only once, regardless of how many times new is executed)
var Obj = function() {};
Obj.prototype.foo = function() {};
5) As an anonymous function with a reference (same effect as #1) *
var foo = function() {};
6) As an immediately executed anonymous function (completely anonymous)
(function() {})();
* When I look at this statement, I consider the result. As such, I don't really consider these as anonymous, because a reference is immediately created to the function and is therefore no longer anonymous. But it's all the same to most people.
The first one is simply creating an anonymous function and assigning it to a variable some_func. So using some_func() will call the function.
The second one should be part of an object notation
var obj = {
show:function(value){
// some code here
}
};
So, obj.show() will call the function
In both cases, you are creating an anonymous function. But in the first case, you are simply assigning it to a variable. Whereas in the second case you are assigning it as a member of an object (possibly among many others).
First is local (or global) variable with assigned anonymous function.
var some_name = function(val) {};
some_name(42);
Second is property of some object (or function with label in front of it) with assigned anonymous function.
var obj = {
show: function(val) {},
// ...
};
obj.show(42);
Functions are first-class citizens in JavaScript, so you could assign them to variables and call those functions from variable.
You can even declare function with other name than variable which that function will be assigned to. It is handy when you want to define recursive methods, for example instead of this:
var obj = {
show: function(val) {
if (val > 0) { this.show(val-1); }
print(val);
}
};
you could write:
var obj = {
show: function f(val) {
if (val > 0) { f(val-1); }
print(val);
}
};
One way of doing it:
var some_func = function(value) {
// some code here
}
Another way:
function some_funct() {
}
Yet another way:
var some_object={};
some_object["some_func"] = function() {};
or:
var some_object={};
some_object.some_func = function() {};
In other words, they are many ways to declare a function in JS.
Your second example is not correct.
The first one is a function declaration assigned to a variable (at least it should be, despite the fact that it's missing the variable type declaration first), the second one is probably related to a object declaration.
They are called anonymous functions; you can read more about them here:
http://www.ejball.com/EdAtWork/2005/03/28/JavaScriptAnonymousFunctions.aspx
The first example creates a global variable (if a local variable of that name doesn't already exist) called some_func, and assigns a function to it, so that some_func() may be invoked.
The second example is a function declaration inside an object. it assigns a function as the value of the show property of an object:
var myObj = {
propString: "abc",
propFunction: function() { alert('test'); }
};
myObj.propFunction();
The first one...
some_func = function(value) {
// some code here
}
is declaring a variable and assigned an anonymous function to it, which is equivalent to...
function some_func (value) {
// some code here
}
The second one should look like this...
obj = {
show:function(value){
// some code here
}
}
// obj.show(value)
and equivalent to...
//pseudo code
class MyClass {
function show (value) {
// some code here
}
}
obj = new MyClass(); // obj.show(value)
Cheers

Categories