I'm trying to do something like this:
function foo() { alert(this.bar); }
foo.bar = "Hello world";
foo();
That doesn't work because I believe this refers to the global object (window) rather than foo. How do I make it work?
this refer to the object used to call the method. By default, it will be the window object.
In your case, you should get the parameter in the function object directly using the named function as it is available in the scope.
function foo() { alert(foo.bar); }
foo.bar = "Hello world";
foo();
You shouldn't use this as doing something like this:
foo.call({})
this will be equal to the empty object.
Possibly try using prototype:
function foo() {
alert(this.bar);
}
foo.prototype.bar = "Hello world";
new foo(); //new object
Recommended option:
function foo(bar) { //constructor argument
this.bar = bar;
}
foo.prototype.getBar = function() {
alert(this.bar);
};
new foo("Hello world").getBar();
I'd choose to do it this way, as it makes use of the prototype chain.
function Foo() { return (this===window) ? new Foo() : this; }
Foo.prototype.hi = function() { alert(this.bar) };
Foo.prototype.bar = "Hi!";
var tmp = new Foo();
tmp.hi();
Related
What different between assigning property on Object and Object.prototype?
for example
Object.test =function(){};
and
Object.prototype.test =function(){}
The first gives Object a static method that can be invoked directly from the class, without an instance. For example:
Object.test =function(){
console.log('Object test running');
};
Object.test();
Assigning a function to the prototype, on the other hand, allows for instances to run the method:
Object.prototype.test = function() {
console.log('test running on object ', this);
};
// don't use the object constructor, this is just an example:
const obj = new Object();
obj.test();
It might make a bit more sense if you didn't use the built-in Object, which everything inherits from:
function Foo() {}
Foo.checkIfFoo = function(arg) {
return arg instanceof Foo;
};
const f = new Foo();
console.log(Foo.checkIfFoo(f));
Here, foo.checkIfFoo is a helper function on Foo that checks if a passed object is an instance of Foo or not - no instance is required to run checkIfFoo. Functions on the prototype, on the other hand, require an instance to run:
function Foo() {
this.info = 'A Foo instance';
}
Foo.prototype.checkInfo = function() {
console.log(this.info);
};
const f = new Foo();
f.checkInfo();
Note that in ES6+, you can put a function directly on the class with the static keyword:
// roughly equivalent to the snippet with checkIfFoo above
class Foo {
static checkIfFoo(arg) {
return arg instanceof Foo;
}
}
const f = new Foo();
console.log(Foo.checkIfFoo(f));
Whereas a standard method lacks the static keyword:
// roughly equivalent to the snippet with checkInfo above
class Foo {
constructor() {
this.info = 'A Foo instance';
}
checkInfo() {
console.log(this.info);
}
}
const f = new Foo();
f.checkInfo();
I want to load more than one function dynamically:
var str = "function foo() {} function bar() {}";
var functions = eval(???);
functions.foo();
Can this be done with eval? I was only successful with a single function.
With eval. Not recommended.
var str = "function foo() { console.log('foo'); } function bar() { console.log('bar'); }";
eval(str);
foo();
You could use an object and put the functions inside. You can later add a function with assignment.
var functions = {
foo: function () { console.log('foo'); },
bar: function () { console.log('bar'); }
};
functions.foo();
functions.baz = function () { console.log('baz'); }
functions.baz();
eval will execute certain string but it will not return anything. So functions will be undefined
eval will also run the given string in current scope. So the parsed functions will not necessarily be created in global scope.
Sample:
var str = "function foo1() {console.log('foo1')} function bar1() {console.log('bar1')}";
var functions = eval(str);
console.log(functions);
foo1();
(function() {
var str = "function foo2() {console.log('foo2')} function bar2() {console.log('bar2')}";
var functions = eval(str);
foo2();
})()
try {
foo2();
} catch (ex) {
console.log(ex.message)
}
My suggestion, create a new JS file and load it dynamically.
Reference Links:
Why is using the JavaScript eval function a bad idea?
Eval is evil
Dynamically load a JavaScript file
var foo = '( function foo() {} )'
var bar = '( function bar() {} )'
declare function with variable, then use the eval
var result = eval(foo)
result variable get the result of the foo() function
With functions.foo(); you try to access the property foo of the object functions and this will give you an undefined.
Solution
You could replace you string of functions simply with an object like
var functions = {
foo: function() {},
bar: function() {}
}
This avoids also the usege of eval().
Now you can access each property with functions.<functionName>;. You can add propertys dynamicly at runtime in JavaScript. So there is no usecase for eval in your problem
Example
var functions = {
foo: function() { console.log('foo') },
bar: function() { console.log('bar') }
}
function addNewFunction(object, functionName, functionImplementation) {
object[functionName] = functionImplementation
}
addNewFunction(functions, 'ok', function() { console.log('ok') })
functions.foo()
functions.ok()
Trying to understand the scope chain and execution context stack articles from David Shariff's Blog, I've tried to understand closures here
function foo() {
var a = 'private variable';
return function bar() {
alert(a);
}
}
var callAlert = foo();
callAlert(); // private variable
I just wanted to test if inner function has the variable object just from its parent or from the whole scope chain, so I added a nested function repeating the example:
function foo() {
var a = 'private variable';
return function bar() {
return function foobar() {
console.log(a);
};
};
}
var callAlert = foo();
callAlert(); //
And that is not giving any result. It seems the interpreter is not even entering the foobar() function. And the syntax is the same than its parent.
But it works if I divide the function declaration and execution.
function foo() {
var a = 'private variable';
return function bar() {
function ra() {
console.log(a);
};
return ra();
};
}
var callAlert = foo();
callAlert(); // private variable
And really I'm trying to guess why; where's the difference from bar() and foobar() functions.
PS - I'm testing on JSFiddle
function foo() {
var a = 'private variable';
return function bar() {
return function foobar() {
console.log(a);
};
};
}
Here you're returning a function that returns a function, so you need to call that new, doubly nested function
var callAlert = foo()();
DEMO
Or any variation on that theme
var getBar = foo();
var getFooBar = getBar();
getFooBar(); //private variable.
Updated demo
The second example works fine because you're still returning one function—a function that simple calls another function.
return function bar() {
function ra() {
console.log(a);
};
return ra();
};
Is there a way to do:
foo() // return string "foo"
foo.bar() // return string "bar"
?
I tried to experiment with functions and objects. But nothing happened.
function foo() {
return "foo";
}
foo.bar = function() {
return "bar";
};
Or, if you prefer:
var foo = function() {
return "foo";
};
foo.bar = function() {
return "bar";
}
JS functions are a type of object so you can assign properties/methods to them the same as for any other object.
You can call either a function or a class named foo but you can't have both as far as I know. Correct me if I'm wrong. Why would you want a class and a function with the same way anyway? I'm assuming that that's what you want as there is little info in your post
To define a function use this
function foo() {
console.log("foo");
}
And call it like in your example.
To define a class do it like this (here are some other ways to do it).
var foo = {
bar: function() {
console.log("bar");
}
}
And again, call it like you did in your example.
I'm trying something like this:
(function() {
var Foo, foo;
Foo = function(proto) {
var obj, privateMethod, publicMethod;
privateMethod = function() {
return console.log("private", this);
};
publicMethod = function() {
console.log("public", this);
return privateMethod();
};
obj = Object.create(proto);
obj.bar = publicMethod;
return obj;
};
foo = new Foo({
baz: "dooz"
});
foo.bar();
}).call(this);
Obviously this is the object itself when publicMethod is called, but is set to the global object in the privateMethod. I know it can be solved by changing:
return privateMethod();
to:
return privateMethod.call(this);
I know that this get's lost when a function is nested in a function, but did not expect that case here. Do I encounter this JavaScript bug here or is there something that I simply do not understand yet?
Context (this), in javascript, is set by how a function is called, and is in no way a property of the function itself.
obj.bar = function() { console.log(this) };
obj.bar() // obj
obj['bar']() // obj
// But break the function off the object, and this changes
fn = obj.bar
fn() // window
What this example shows us is that the the dot syntax there sets this. Think of obj.bar() is syntax sugar for obj.bar.call(obj).
So your public method gets the right this, because of how it's called in external code.
foo.bar();
But your private method is invoked with no receiver at all.
return privateMethod();
So no context is assigned, and it defaults to the global object.
So given you are creating these functions in the constructor, you have some flexibility.
You could assign the proper value of this in the constructor to something else, and use that in your private functions. (Likely the best option)
var self = this;
privateMethod = function() {
return console.log("private", self);
};
Or if your JS target engine support Function.prototype.bind (not all do, sadly) you could do:
privateMethod = function() {
return console.log("private", this);
}.bind(this);
Which will return a function that has an assigned context, no matter what.
Or you could bind it manually yourself.
_privateMethod = function() {
return console.log("private", this);
}
Foo = function(proto) {
privateMethod = function() {
_privateMethod.call(this);
}
}
You're calling foo.bar(). This means the function bar() is called on foo, meaning this is foo inside bar().
In your case foo is a Foo object obj, and bar() is publicMethod.
When publicMethod() calls privateMethod(), there's no context, so this becomes the global this (window).