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.
Related
Is there a way to access properties in nested functions like that :
function func(){
this.new_func=function(){
console.log("something");
return 'something';
}
this.someValue=7;
return function(){
return "something_diff";
};
}
var obj=new func();
obj(); //works with returning "something diff"
obj.new_func(); // TypeError: obj.new_func is not a function
obj.someValue; // undefined
I need to delete whole "return function()..." part in order to access "someValue" and "new_func()". Why is it acting like that, and is there a way to somehow access that properties, while still returning another function ??
When you have a constructor that returns an object, that object replaces whatever you assigned to this. So indeed, the members new_func and someValue are lost.
To combine the returned function together with the other members, you can do this:
function func() {
var f = function() {
return "something_diff";
};
f.new_func = function() {
console.log("something");
return 'something';
}
f.someValue = 7;
return f;
}
var obj = new func();
console.log(obj());
obj.new_func();
console.log('someValue:', obj.someValue);
You can do it like this:
var parentFunction = function() {
var nestedFunction = function() {
var value = "nestedValue";
var moreValues = "more values";
return {
value: value,
moreValues: moreValues
}
}
var anotherNestedFunction = function() {
var anotherValue = "nestedValue";
return anotherValue;
}
return {
nested: nestedFunction,
another: anotherNestedFunction
}
}
Then:
var newFunction = new parentFunction();
var nested = newFunction.nested();
console.log("nested value: ", nested.value);
console.log("another nested value: ", newFunction.another);
Here is a working example:
Why is it acting like that, and is there a way to somehow access that properties, while still returning another function ??
Because of the pharenteis:
var obj=new func();
Basically you're firing your function and what is stored the variable obj is what the "func" returns.
In order to access to private properties, you should look at the Closures: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
I have a javascript object from which I created from a constructor.
var obj = new Obj();
It has several functions but I wish to also use it as follows;
obj();
Obj is defined as:
function obj() {
this.blah = function () {
};
}
How can I do this?
It would be easier to have a function you call which returns an arbitrary function that is treated as both an object and a function. Each one would be unique, and you would not need to use new.
function Obj() {
var ret = function(){
console.log('Hello');
};
ret.blah = function () {
console.log('World');
};
return ret;
}
var obj = Obj();
obj();//Hello
obj.blah();//World
You can create properties on function objects. For instance, if you have the function
function foo() {
return "bar";
}
You can set a property on foo.
foo.baz = 42;
So now you can call foo and get the result "bar", and you can access its baz property.
I think you are looking for 'closure' here.
Try:
function MyObject(/* constructor params */) {
//assign properties to 'this'
return function() {
return this; //<== placeholder implementation
}.bind(this);
}
var obj1 = new MyObject();
Now if you do console.log(obj1) you will see function() { [...] } and you will be able to do obj1() to execute your function.
As a bonus in the code above, I also added this binding in the 'closure' as you will need it in most cases that you are doing anything interesting.
In JavaScript I am looking for a way to use bind() on an anonymous and async function.
Example:
exports.foo = function () {};
exports.foo.prototype = {
load : function(id) {
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
});
}
};
I got this working by making the functions non-anonymous, but I think it makes my code look ugly. Especially after having 4 different anonymous functions in a row.
exports.foo = function () {};
exports.foo.prototype = {
load : function(id) {
function _load(object) {
this.object = object;
}
var _loadThis = _load.bind(this);
var query = new Parse.Query("SomeObject");
query.get(id).then(_loadThis);
}
};
Is there a better way?
Well it's not necessarily "better", but you can call .bind() directly after the closing brace of your function instantiation expression:
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
}.bind(this));
A function instantiation expression gives you a function object reference, so putting a . after it and calling bind makes sense. What gets passed to the .then function, therefore, is the return value from the call to .bind.
This syntax is not correct:
exports.foo.prototype = {
load = function(id) {
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
});
}
};
The prototype is an object who's properties are defined as load: function() {}, not load = function() {}.
It should be:
exports.foo.prototype = {
load: function(id) {
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
});
}
};
A simple way to do it is to declare a variable to the correct 'this' and use closuers to keep a reference to it.
exports.foo = function () {};
exports.foo.prototype = {
load : function(id) {
var self = this;
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
self.object = object; // this is the wrong this
});
}
};
I have the following code with and without a module pattern. I have given the results right next to the execution. In the module pattern, I am able to change foo and set_inner, while in the function object (non-module), I can't change foo and set_inner.
module pattern:
var someObj = (function () {
var instance = {},
inner = 'some value';
instance.foo = 'blah';
instance.get_inner = function () {
return inner; };
instance.set_inner = function (s) {
inner = s; };
return instance; })();
someObj.get_inner();//some value
someObj.set_inner("kkkk");
someObj.get_inner();//kkk
someObj.foo;//blah
someObj.foo="ddd";
someObj.foo;//ddd
non-module:
var someObj = function () {
var instance = {},
inner = 'some value';
instance.foo = 'blah';
instance.get_inner = function () {
return inner; };
instance.set_inner = function (s) {
inner = s; };
return instance; };
someObj().get_inner();//some value
someObj().foo;//blah
someObj.foo="aaa";
someObj().foo;//blah
someObj().set_inner("kkk");
someObj().get_inner();//some value
Any help is much appreciated. Thanks!
Your "module" example creates a single object, referred to by instance. The anonymous function is immediately invoked, and returns that object. So someObj refers to instance.
Your "non-module" example creates a new object each time you invoke it. The anonymous function is not immediately invoked. Instead, it has to be called every time you want to use it.
It would behave the same way if you assigned the return value to a variable and referred to that, instead of repeatedly invoking someObj:
var obj = someObj();
obj.get_inner(); //some value
obj.foo; //blah
obj.foo="aaa";
obj.foo; //aaa
//etc...
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');