I have this code example:
function s () {
this.func = [];
this.func.addF = function (str) {
this.func.push(str);
}
}
When I create an Instance of that object:
var a = new s ();
a.func.addF ("hello");
I get an error saying: Uncaught TypeError: Cannot read property 'push' of undefined.
I can understand that this.func is undefined at that point, but what should I do to make this work. Pls help.
There is a problem with this. In javascript, this point to the binding context or what was used to invoke the function call. The value of this is determined by how a function is called.
function s () {
var self = this;
self.func = [];
self.func.addF = function (str) {
self.func.push(str);
}
}
var a = new s ();
a.func.addF("hello"); // Display 'hello'
Are you trying to add the method to the inner object (the array) or the outer object (the one constructed by s)?
If the function is intended to be added to the outer object
function s () {
this.func = [];
this.addF = function (str) {
this.func.push(str);
}
}
If the function is intended to be added to the inner (array) object
function s () {
this.func = [];
this.func.addF = function (str) {
this.push(str);
}
}
The reason has to do with how this is defined. When you call the method like this:
a.func.addF ("hello");
the variable this does not refer to a, it refers to a.func. a.func does not have a property func, but it does have the method push, so if you really intended to add the function to the array object itself, then just use this.push.
Related
I have a list of objects I am looping over; each of these objects has a property on it which is a function referring to this. If I create a list of callbacks based on my objects, it seems that I have to "double-wrap" the this-dependent function in order to maintain the correct references. I don't understand why this is - can anyone explain?
function Pokemon(name) {
this.name = name;
this.sayName = function() {
console.log(this.name);
};
}
function runFunctions(arrayOfFunctions) {
for (var i = 0, fn; fn = arrayOfFunctions[i]; i++) {
fn();
}
}
var monsters = [
new Pokemon('Charmander'),
new Pokemon('Squirtle'),
new Pokemon('Bulbasaur')
];
var unclosedCalls = [];
var closedCalls = [];
for (var i = 0, monster; monster = monsters[i]; i++) {
var unclosedCall = (function(m) {
return m.sayName
})(monster);
var closedCall = (function(m) {
return function() {
m.sayName();
}
})(monster);
unclosedCalls.push(unclosedCall);
closedCalls.push(closedCall);
}
console.log('--start')
runFunctions(unclosedCalls); // doesn't work
console.log('----')
runFunctions(closedCalls); // works
console.log('--end')
closedCalls is the list of double-wrapped callbacks.
I don't get why m in each creation of unclosedCall is not actually closed over.
Here is a jsbin with my code: http://jsbin.com/qivilusuje/1/edit?js,console,output
The problem with the "unclosed" calls is that the function reference that you return (m.sayName) is immediately disassociated from the variable m from which the function property was retrieved.
A function reference doesn't know anything about which object it was retrieved from so therefore when the function is eventually invoked it has no "context" - this will be set to the global object instead of the object that originally had this function as a property:
var obj = {
func : function() { console.log(this) }
}
obj.func() // outputs "obj" because a.b() calls "b" with "this" === "a"
var ref = obj.func;
ref(); // outputs "window"
To fix it you can have the unclosed call do return m.sayName.bind(m), although having got that far there's no need for the IIFE either, and it would work just as well to say:
var unclosedCall = monster.sayName.bind(monster);
I have this simple Javascript object that calls its own prototype method in one of its local methods. [SEE MY EDIT]
var Obj = function() {
function inner() {
this.exported();
}
this.exported = function() {
alert("yay!");
};
};
var test = new Obj();
Obj.exported();
However, I get the error TypeError: Object function() {...} has no method 'exported'.
Any idea how this should be done?
EDIT:
whoops, just realized I never called inner(), but thanks Patrick for answering that part anyways. Here is a better example
var Obj = function() {
this.exported = function() {
inner();
};
function inner() {
this.yay();
}
this.yay = function() {
alert("yay!");
};
};
var test = new Obj();
test.exported();
I get TypeError: Object [object global] has no method 'exported'
should be used
test.exported();
instead of
Obj.exported();
You should invoked exported() method over the test object, not over the Obj constructor.
UPDATE
After reached inside the function inner(){...}. this is refers to global window not Obj, so pass the actual object this from inner(this) and do invoke export() from that passed object into function inner(cthis){...}, something like.
function inner(cthis) {
//----------^--get Obj on here
cthis.exported();
}
this.exported2 = function() {
inner(this);
//------^--pass Obj from here
};
DEMO
to call exported you need to call it off the variable you assigned the instance to:
test.exported();
Also for the inner function you cannot use this there to access the Obj object as it refers to window.
save a reference to this and then use that to call the function
var Obj = function() {
var _this = this;
function inner() {
_this.exported();
}
this.exported = function() {
alert("yay!");
};
};
I have this code here:
var myRequest = new httpReq.myRequest(buffer,socket);
if(!myRequest.hasSucceded()){ //return error
return;
}
arr=myRequest.getCookies();
....
and i definitely have this function on my myRequest object:
function myRequest(buffer, socket) {
...
this.cookies = new Array();
...
//returns the cookie array
function getCookies() {
return this.cookies;
}
...
}
exports.myRequest = myRequest;
and i get an error saying:
TypeError: Object #<myRequest> has no method 'getCookies'
Y U NO GIVE COOKIES???
help please...
You are declaring getCookies as a local function.
To call it externally, you need to create a property getCookies on your object so you can call it.
Try this:
function myRequest(buffer, socket) {
...
this.cookies = new Array();
...
//returns the cookie array
this.getCookies = function() {
return this.cookies;
}
...
}
You also could just do myRequest.cookies instead of myRequest.getCookies()
function myRequest(buffer, socket) {
this.cookies = [];
}
myRequest.prototype.getCookies = function () {
return this.cookies;
};
First, declaring getCookies inside constructor directly causes this method to be a private method, which only lives within the constructor.
Second, usually it is considered a good practice to define the prototype getCookies outside the constructor. If it is defined in the constructor (like, this.getCookies = function () {...}), this method would need to be initialized every time when this prototype is instantiated.
I have been trying out some js code in jsfiddle and it seems I cant get all these combinations of codes below to work..
//combination #1
function get_set() {
this.get = function () {
document.write("get");
};
this.set = function () {
document.write("set");
};
};
var x = get_set; // storing function reference in x
x.get(); //invoking doesnt work.
//combination#2
var get_set = function() {
this.get = function () {
document.write("get");
};
this.set = function () {
document.write("set");
};
};
get_set.get(); //doesnt work as well..
Is there something that I miss? Thanks in advance for constructive suggestion/pointing out any errors. Would appreciate any help.
You either have to create a new instance of get_set
var x = new get_set();
or inside get_set you have to use return this; for this example to work.
Your get_set function is a constructor function. It's intended to create ('construct') instances of itself. In order to make that work you need the keyword new. So
var getset = new get_set;
creates an instance of get_set. Now the methods getset.set and getset.get are available.
In this case maybe you could create a unique instance using an Object literal:
var get_set = {
get: function () {
document.write("get");
},
set: function () {
document.write("set");
}
};
Now you don't need the new keyword and the methods are available right away (get_set.get, get_set.set)
Use x=new get_set; That will work.
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");