A JavaScript newbie here. I have this following code:
function testObject(elem) {
this.test = "hi";
this.val = elem;
console.log(this.test+this.val);
echo();
function echo () {
console.log(this.test+this.val);
}
}
var obj = new testObject("hello");
When it is run, I expect "hihello" to be outputted twice in the console. Instead it outputs as expected the first time but returns NaN the second time.
I'm sure I'm missing something here. I thought that the internal function can access the vars held outside. Can someone please guide me? I'm more of a functional UI developer and don't have much experience with OO code.
Thanks!
The problem is that inside echo the this value points to the global object, and this.test and this.val (which are referring to window.test and window.val) are undefined.
You can set the this value of echo by invoking it like:
echo.call(this);
That happens because you were invoking the function by echo();, then the this value is implicitly set to the global object.
Give a look to this question to learn how the this value works.
Edit: For being able to calling just echo(); you should persist the this value from the outer function context, there are a lot of ways to do it, for example:
//...
var instance = this; // save the outer `this` value
function echo (){
console.log(instance.test+instance.val); // use it
}
echo();
//...
Or
//...
var echo = (function (instance) {
return function () {
console.log(instance.test+instance.val);
};
})(this); // pass the outer `this` value
echo();
//...
You could also do this:
function testObject(elem) {
this.test = "hi";
this.val = elem;
console.log(this.test+this.val);
this.echo = function () {
console.log(this.test+this.val);
}
this.echo();
}
var obj = new testObject("hello");
Whenever you call this.echo() or obj.echo(), this will be bound to the object invoking the function.
Personally, I find it elegant to declare class methods like this:
function testObject(elem) {
this.test = "hi";
this.val = elem;
this.echo();
}
testObject.prototype = {
echo: function () {
console.log(this.test + this.val);
}
}
var obj = new testObject("hello");
Related
I am currently working on modules but my confusion is that when I code return object in function it can called outside function scope, but when I code standard object like var obj = {some: something} then this can't be called outside the function scope. Why and how?
// Return Object
var ray = (function(){
return {
speak: function (){
console.log("Haseeb");
}
};
})();
ray.speak();
// Standard Object
var ray = (function(){
var obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
obj.speak();
Assuming that you meant to write ray.speak(); instead of obj.speak();;
// Standard Object
var ray = (function(){
var obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
In this snippet, when anonymous function is executed it returns nothing back to ray variable, so when you try to access speak() method from ray, it throws an error saying Cannot read property 'speak' of undefined.
But in your first snippet, the anonymous function does return an object with speak method so you can call, ray.speak().
// Standard Object
var ray = (function(){
var obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
obj.speak();
This does not work because of how lexical scoping works. Obj on the outside has no context to what is defined inside of the function because the obj is declared inside the block scope of the function. If, however obj was declared in the same scope, it will work as expected.
var obj;
// Standard Object
var ray = (function(){
obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
obj.speak();
ray.speak() will not work because it does not have a binding to obj.
return obj={...} will be a solution for this problem.
Understanding JavaScript variable scope would help:
http://www.w3schools.com/js/js_scope.asp
Now coming to your code.
In the first snippet, the variable 'ray' gets assigned the value returned by the the self executed function, which is the object returned. It is similar to this:
var ray = {
speak: function (){
console.log("Haseeb");
}
};
So now the statement below is valid as 'ray' has a property 'speak'
ray.speak();
However, in the second part of the snippet, nothing is returned by the self executed function, so, it is similar to:
var ray = undefined;
Now the statement 'ray.speak()' is same as executing 'undefined.speak()', which would throw an error, obviously.
Also, executing obj.speak is same as executing 'undefined.speak()', because the variable 'obj' is only available inside that self executing function. Outside the function, 'obj' is not defined.
Hope this helps. :)
Edit:
Explanation for your question about the return statement:
The return statement returns whatever is the output of the code/statement in front of it.
Examples:
var a = 2;
return a; // will return a's value, i.e. '2'
var obj = { x:1 };
return obj; // will return the obj variable's value i.e. { x:1 }
var a = 1;
return a > 1; // will return false i.e. what 'a > 1' outputs after execution
so if you write
return obj = { x:1 };
this will return what the assignment 'obj = { x:1 }' outputs, which is obj's assigned value.
Now coming to your code
var ray = (function(){
return obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
Here the return statement doesn't make obj available to the scope outside the function, it just returns the value of obj, which is then assigned to 'ray'.
The reason that you are able to do obj.speak() without getting any exceptions is that you have used the variable obj without declaring it inside the function using 'var' keyword, which results in 'obj' getting automatically declared in the global scope. And that is why you are able to access 'obj' outside of the function too.
If you change your code to this:
var ray = (function(){
var obj;
return obj = {
speak: function (){
console.log("Haseeb");
}
}
})();
You will get exception while trying to execute obj.speak() outside the function. Because 'obj' is now declared and available only inside the function.
I would suggest reading some more tutorials about variable scope in JavaScript and playing around a bit on the console. :)
Hope this helps :)
I'm trying to understand how to best use the JavaScript module pattern. My problem is that it seems there's no way to refer to the module from within itself, because this is set to the Window object.
I've got this simple test code:
var Test = function() {
var that = this;
return {
something: function() {
console.info(that);
}
}
}
var test1 = Test();
test1.something();
var test2 = Test();
test2.something();
Both test1 and test2 print a reference to the Window object instead of the module itself.
Any idea how to change it so that I have a valid this inside the module?
If you did
var test1 = new Test()
You could then do
test1.something();
An alternative module structure would be to do something like this:
var myModule = function () {
var obj = {};
obj.something = function () {
return console.log(obj);
};
obj.something2 = function () {
return console.log(obj === this); // true
};
return obj;
};
var test = myModule();
test.something();
test.something2();
Hope this helps
I think you're confusing the JavaScript module pattern with JavaScript constructor functions.
JavaScript constructor functions
If you write a function and call it with the new keyword in front of it, then that function is called as a constructor function.
It will automatically return a new object, that you can refer to within the constructor function using the this keyword.
var Test = function() {
var that = this;
this.something = function () {
console.info(that);
console.info(this);
};
}
var test1 = new Test();
test1.something();
You can return your own object instead, but you wouldn't normally do that in a constructor, you'd just use this instead:
var Test = function() {
var that = this;
return {
something: function () {
console.info(that);
console.info(this);
}
};
}
var test1 = new Test();
test1.something();
If you don't call it with the new keyword in front of it, then it's called like a regular function, meaning any references to this inside of it refer to the object of which the function is a property (which, in the absence of anything else, will be the global object, which in web browsers is window).
var geoff = {
Test: function () {
var that = this;
return {
something: function () {
console.info(that);
}
};
}
};
var test2 = geoff.Test();
var test3 = Test();
Note: with constructor functions, you'd normally define methods on their prototype object, so that the methods don't get unnecessarily redefined for each object you create using the constructor function:
var Test = function() {
this.else = "Something Else"
}
Test.prototype.something = function () {
console.info(this);
}
Test.prototype.somethingElse = function () {
console.info(this.else);
}
var test4 = new Test();
test1.somethingElse() // Logs "Something Else"
(Note that if you return your own object from the constructor function as we mentioned above, then you won't be able to access methods on the prototype object any more.)
Also note that each time you call a constructor function, it returns a new object. You can pass parameters into a constructor function (just like you can with any other function) and use them to customise the object returned:
var Test = function(else) {
this.else = else;
}
Test.prototype.somethingElse = function () {
console.info(this.else);
}
var test1 = new Test("Something else");
var test2 = new Test("Something else again");
test1.somethingElse(); // Logs "Something else"
test2.somethingElse(); // Logs "Something else again"
The problem you have is because this refers to an object, but Test() isn't an object; it's just a function. The object that owns Test() is the Window object (because Test is in the global scope), so therefore that's what you get back when you reference this from within Test().
You may want to try something like this:
var testObj = {
Test : function() {
var that = this;
return {
something: function() {
console.info(that);
}
}
}
}
Now you can call testObj.Test(); and you'll get a reference back to the testObj object.
Hope that clarifies things a bit.
I want to be able to assign a property to a function inside the function itself. I do not want to assign it to the object of invocation. So I want the equivalent of doing this:
var test = function() {
return true;
};
test.a = 'property on a function';
alert(test.a);
Instead of this, where the property is assigned to a global object:
var testAgain = function() {
this.a = "this property won't be assigned to the function";
return true;
};
testAgain();
alert(window.a);
Edit: To clarify, I'm wondering if there's something like this:
var test = function() {
function.a = 'property on a function';
};
alert(test.a); // returns 'property on a function'
Without knowing that the function is called test or having to execute it.
I know of course this isn't valid syntax
[is there a way to set a property on a function] without knowing that the function is called test or having to execute it.
Emphasis mine.
You can set a property on a function without knowing what its global variable name is necessarily going to be, however you do have to have a reference to the function in one way or another.
The module pattern is as close of a fit as I can think of:
window.test = (function () {
//the function could be named anything...
function testFn() {
...code here...
}
//...so long as the same name is used here
testFn.foo = 'bar';
return testFn;
}());
window.test.foo; //'bar'
The outer closure prevents testFn from being accessed anywhere globally, so all other references will have to use window.test.
This part of the answer is associated with the prior version of the question.
The simplest way of doing this is to use a named function:
var test = function testFn() {
testFn.foo = 'bar';
return true;
};
test.foo; //undefined
test();
test.foo; //'bar'
A better way of doing this is to use the module pattern so that you don't accidentally create issues with global leakage:
var test = (function () {
function ret() {
ret.foo = 'bar';
return true;
}
return ret;
}());
test.foo; //undefined
test();
test.foo; //'bar'
var testAgain = function() {
arguments.callee.a = "this property won't be assigned to the function";
return true;
};
testAgain();
alert(testAgain.a);
You can do this by simple using the name to assign the property like this:
var test = function () {
test.a = 'a';
return true;
};
When test is invoked, the property will be set.
Demo
You could use arguments.callee, as su- said, but that's considered really bad practice. Also, it won't work in strict mode.
var test = function() {
test.a = 'a';
};
Or you can use prototypes, read more here.
Consider this piece of code
var crazy = function() {
console.log(this);
console.log(this.isCrazy); // wrong.
}
crazy.isCrazy = 'totally';
crazy();
// ouput =>
// DOMWindow
// undefined
From inside crazy() 'this' refers to the window, which I guess makes sense because normally you'd want this to refer to the object the function is attached to, but how can I get the function to refer to itself, and access a property set on itself?
Answer:
Don't use arguments.callee, just use a named function.
"Note: You should avoid using arguments.callee() and just give every function (expression) a name." via MDN article on arguments.callee
I think you are asking for arguments.callee, but it's deprecated now.
https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments/callee
var crazy = function() {
console.log(this);
console.log(arguments.callee.isCrazy); // right.
}
crazy.isCrazy = 'totally';
crazy();
// ouput =>
// DOMWindow
// totally
As rfw said, this is the most straight forward way to go if the function has one single name:
var crazy = function() {
console.log(crazy);
console.log(crazy.isCrazy);
};
crazy.isCrazy = 'totally';
crazy();
In case it may have different names, or you wanted to pass it around, it must be wrapped in a closure:
var crazy = (function(){
var that = function() {
console.log(that);
console.log(that.isCrazy);
};
return that;
})();
crazy.isCrazy = 'totally';
crazy();
Bind the function to itself (taking a hint from answers by #ArunPJohny and #BudgieInWA):
crazy = crazy.bind(crazy);
This will give you access from the function to its properties via this.
> crazy()
function () {
console.log(this);
console.log(this.isCrazy); // works now
}
This seems like a better solution than the accepted answer, which uses the callee feature which is deprecated and doesn't work in strict mode.
You could also now have the function call itself recursively with this() were you so inclined.
We will call this self-thisifying. Write a little utility function:
function selfthisify(fn) { return fn.bind(fn); }
crazy = selfthisify(crazy);
crazy();
Or, if you prefer more "semantic" names, you could call it accessOwnProps.
If you're a syntactic sugar type of person, you could add a selfthisify property to the Function prototype:
Object.defineProperty(Function.prototype, 'selfthisify', {
get: function() { return this.bind(this); }
});
Now you can say
crazy.selfthisify();
You have to give it its own name, so:
var crazy = function() {
console.log(crazy);
console.log(crazy.isCrazy);
}
crazy.isCrazy = 'totally';
crazy();
The variable this is only applicable in the scope of an object, for instance, if you invoked your version of the crazy function with crazy.call(crazy), it will call the function in the context of the function crazy and all would be well.
This has to deal with the scope of the function crazy. If can pass any scope to a function using the function call().
Instead of
crazy();
Use
crazy.call(crazy);
For details refer
http://odetocode.com/blogs/scott/archive/2007/07/05/function-apply-and-function-call-in-javascript.aspxhttps://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Callhttp://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx
You can use the call method
var crazy = function() {
console.log(this);
console.log(this.isCrazy);
}
crazy.isCrazy = 'totally';
crazy.call(crazy);
// calls crazy using crazy as the target, instead of window:
// functionToCall.call(objectToUseForThis);
Though if your function only ever has one name, you can do this:
var crazy = function() {
console.log(crazy);
console.log(crazy.isCrazy);
}
crazy.isCrazy = 'totally';
crazy();
Easiest way to make the function itself available in its body is to do
var crazy = function crazy2() { crazy2(); }, it's okay for crazy and crazy2 to have the same name since the first occurrence is the name in the outer scope and the second is the name in the function body.
Or simply do function crazy() { crazy(); } which will define crazy in both scopes.
how can I get the function to refer to
itself?
The idea of 'itself' does not exist with functions. What you need is an object and not just a function. An object has knowledge of itself available through the keyword 'this'. Within a function, 'this' points to the global object - in this case the window object. But if you use your function as a constructor function to create an object (using the new operator) then the object's 'this' pointer will point to the object itself.
i.e this points to the object if you write:
var anObject = new crazy();
So you can re-write your code as follows:
var crazy = function() {
this.printMe = function(){
console.log(this);
console.log(this.isCrazy);
}
}
var anObject = new crazy(); //create an object
anObject.isCrazy = 'totally'; //add a new property to the object
anObject.printMe(); //now print
In case you wish to add the property before the object is created, then you have to add the property to the function's prototype as follows:
var crazy = function() {
console.log(this);
console.log(this.isCrazy);
}
crazy.prototype.isCrazy = 'totally'; //add the property to the function's prototype
var anObject = new crazy(); //invoke the constructor
See more on my blog for a detailed explanation of these concepts with code-samples.
Are you actually trying to create an object 'class'?
function crazy(crazyState) {
this.isCrazy = crazyState;
console.log(this);
console.log(this.isCrazy);
}
crazy.prototype.alertMe = function() { alert('I am '+ this.isCrazy +' crazy.'); }
var crazyObj = new crazy('totally');
crazyObj.alertMe();
crazyObj.isCrazy = 'not';
crazyObj.alertMe();
Funny that you should ask, mate. I just went through this same issue for a different purpose. The quick version of the final code is:
$a = function() {};
$ = function() {
if (!(this instanceof $)) {
return new $();
}
this.name = "levi";
return this;
};
//helper function
var log = function(message) {
document.write((message ? message : '') + "<br/>");
};
log("$().name == window.name: " + ($().name == window.name)); //false
log("$().name: " + $().name); //levi
log("window.name: " + window.name); //result
log();
log("$a instanceof $: " + ($a instanceof $)); //false
log("typeof $a: " + (typeof $a)); //function
log("typeof $: " + (typeof $)); //function
The critical piece:
if (!(this instanceof $)) {
return new $();
}
If this isn't pointing to an object of the right type, then it makes a new one, which will properly scope this. The rest of the code is just there for verification that it does indeed work as intended.
In order to make you code to work follow below
function crazy_object (crazy) {
this.isCrazy = crazy
}
var create_crazy = new crazy_object('hello') //creating object
console.log(create_crazy); //=> { isCrazy = 'hello' }
var crazy = function() {
console.log(this); //=> { isCrazy = 'totally' }
console.log(this.isCrazy); //=> 'totally'
}
create_crazy.isCrazy = 'totally'; //=> isCrazy = 'totally'
//below we pass the created object in function crazy.
//And doing that we can use the keywork `this` and refer to the object
crazy.call(create_crazy, null);
Using the call and apply method we can pass to a function a
property,and in that function we can use the property with the keyword this
For example:
function speak (message) {
console.log(`A person with name ${this.name} say ${message}`);
}
speak.call({ name: 'Roland' }, 'Javascript is awesome');
To use it with property:
function speak (message) {
console.log(`A person with name ${this.name} say ${message}`);
}
var name = 'Roland'
speak.call({ name }, 'Javascript is awesome');
I'm wondering if any of yall have any insight as to how one could execute a function by reference in javascript.
http://mootools.net/shell/yL93N/1/
Any discussion would be cool.
-Chase
looking at your mooshell, the way i'd handle it in mootools is this:
http://mootools.net/shell/yL93N/10/
var proxyFunction = new Class({
message: "hello",
Binds: ['passByReference','sayit'],
passByReference: function(func) {
// console.log(this, this[func]);
if (this[func] && $type(this[func]) === "function")
this[func]();
},
sayit: function() {
alert(this.message);
},
killit: function() {
document.write('we\'re dead');
}
});
$('tryit').addEvent('change',function(e){
new proxyFunction().passByReference(this.get('value'));
});
// or have a permanent proxy instance if you call methods of the class often and need it to change things.
var proxy = new proxyFunction();
$('tryit').addEvent('change',function(e){
proxy.passByReference(this.get('value'));
});
the advantage of doing so is that all your proxied functions are behind a common object, don't pollute your window namespace as global variables and can share data that relates to the event.
Not exactly sure what you mean, but you can do this:
var func = window.alert;
var args = ["hello world"]
func.apply(window, args)
Globally-defined functions (and variables) are visible as members of the global window object.
Members of an object can be fetched by name using the square bracket notation: o['k'] is the same as o.k. So, for your example:
var function_name= $(this).val();
window[function_name]();
Like this?
function blah() {
...do stuff
}
myref = blah
myref()
The best way is to do:
func.call();
Function variables in JavaScript already are references. If you have a function:
var explode = function() { alert('boom!'); };
You can pass explode around as an argument, and it's only passing a handle to that function, not the entire function body.
For proof of this, try:
explode.id = 5;
var detonate = explode;
alert(detonate.id); // => 5
explode.id = 6;
alert(detonate.id); // => 6
functions are first class objects in Java Script. Effectively this means that you can treat it very much as if it were a variable, and pass it anywhere that you would expect a variable.
e.g.
var myFn = function() { alert('inside anonymous fn'); }
function callMyFn(paramFn)
{
paramFn();
}
callMyFn(myFn); //inside anonymous fn
function MyFnHolders(argFn)
{
this.argFn = argFn;
this.fieldFn = function() {
alert('inside fn field');
}
}
var myFnHolders = new MyFnHolders(myFn);
myFnHolders.argFn(); //'inside anonymous fn'
myFnHolders.fieldFn(); //'inside fn field'
//etc
so passing a function by ref can be done simply by assigning it to a variable and passing it around.
Here's one with a closure for your arguments...
function Runner(func, args) {
return function() { return func.apply(window, args); };
}
var ref = new Runner(window.alert, ["hello world"]);
ref();