JavaScript Callback/this confusion with require.js / objects - javascript

I try to use the following structure in my app: https://gist.github.com/jonnyreeves/2474026
I try to register some callback inside my constructor. I made an example using jquery, actually it's leaflet maps, but the difference shouldn't matter.
function Person() {
this.name = "abc";
$("#something").onSomeEvent(function() {
this.name = "cde";
});
}
How do I properly reference my object-property name, inside the callback?

You can use something like this:
function Person() {
this.name = "abc";
$("#something").onSomeEvent(function() {
this.name = "cde";
}.bind(this));
}

function Person() {
var self = this;
self.name = "abc";
$("#something").onSomeEvent(function() {
//this is right if you need
self.name = "cde";
});
}
you can use $('#someting') with right this.
if you use bind to solve the problem,in the callback this is wrong.

Use bind, which is not supported in older IEs, or jquerys proxy
function Person() {
this.name = "abc";
$("#something").onSomeEvent(function() {
this.name = "cde";
}.bind(this));
}
function Person() {
this.name = "abc";
$("#something").onSomeEvent($.proxy(function() {
this.name = "cde";
},this));
}

Related

Why myObject.function() throwing 'is not a function' error? (trying to learn functional instantiation)

I am trying to create a class using a function and giving it some props and a method. If I do the same thing in C# in class-based way and call the mothod this will work fine but in JS it gives me an error. My question is why it behaves in a different way.
code snippet:
function Animal (name) {
let animal = {}
animal.name = name;
animal.eat = function (){
console.log(`${this.name} is eating`)
}
}
let myAnimal = new Animal('dog');
console.log(myAnimal.eat()); //Uncaught TypeError: myAnimal.eat is not a function at proto.js:11
This would be the prototypical way to achieve that in JavaScript:
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(`${this.name} is eating`)
}
new Animal('Pooch').eat();
Or with the introduction of classes (since ECMAScript 2015):
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} is eating`)
}
}
new Animal('Pooch').eat();
well if Animal is going to act as a constructor of your sort of class, then you would need to write it like a proper constructor, i.e. drop the let animal = {} bit, and just set properties on this:
function Animal (name) {
this.name = name;
this.eat = function (){
console.log(`${this.name} is eating`)
}
}
let myAnimal = new Animal('dog');
myAnimal.eat();
now this approach has the downside of creating a new function eat() for each instance of Animal instead of binding an existing function eat() to each instance, which is what happens normally with classes. that you can achieve by this:
function Animal (name) {
this.name = name;
}
Animal.prototype.eat = function (){
console.log(`${this.name} is eating`)
}
let myAnimal = new Animal('dog');
myAnimal.eat();
which is actually the proper way people used to define classes in javascript before class was introduced.
however, you can also drop the whole class-like concept, and just have an Animal() function that gives out an object with desired properties:
function Animal (name) {
let animal = {};
animal.name = name;
animal.eat = function (){
console.log(`${this.name} is eating`)
}
return animal;
}
let myAnimal = Animal('dog');
myAnimal.eat();
note how in this approach you have let myAnimal = Animal('dog') instead of let myAnimal = new Animal('dog'), as Animal() is no longer a constructor.
reminder: this is an explanation of how you can instantiate objects with a function, and by no means the recommended way of defining classes in javascript. in older environments, the prototype approach is the recommended way, for newer environments, just use class.
Go with Robby's approach above. For correcting your code, you missed a statement return animal; :)
function Animal (name) {
let animal = {}
animal.name = name;
animal.eat = function (){
console.log(`${this.name} is eating`)
}
return animal;
}
let myAnimal = new Animal('dog');
console.log(myAnimal.eat());

TypeError: ... is not a function

My JavaScript code in NodeJS results in:
TypeError: ninja.changeName is not a function
Following is my code:
function Ninja(name){
this.name = name;
var changeName = function(name2) {
this.name = name2;
}
}
var ninja = new Ninja("John");
ninja.changeName("Bob");
console.log(ninja.name);
What's wrong with the code?
var changeName will just create a reference to a function which will be lost once the function is done executing.
You must assign the function as a property of the Ninja function instead:
function Ninja(name) {
this.name = name;
this.changeName = function(name2) {
this.name = name2;
}
}
var ninja = new Ninja("John");
ninja.changeName("Bob");
console.log(ninja.name);
var changeName = function(name2) {
this.name = name2;
}
You are declaring a function but not attaching that to the object.
It should be
this.changeName = function(name2) {
this.name = name2;
}
So that the property changeName as a function attached to the object.
You are assigning a function to a variable. This isn't the same as setting a function in the objects prototypal inheritance structure and the variable changeName is only in scope within the context of Ninja.
You can assign the function to this.changeName (important that you're binding to this) like the following:
function Ninja(name){
this.name = name;
this.changeName = function(name2) {
this.name = name2;
}
}
Or you could use prototypes:
function Ninja(name){
this.name = name;
}
Ninja.prototype.changeName = function(name2) {
this.name = name2;
}
Although these approaches look fairly similar, the difference is very important. The first approach creates a new function for every Ninja created. The second approach will use the same function for each object. To look into the reason to use prototypal inheritance, there are various blog posts scattered around the internet.
You are declaring the changeName as a variable but not binding it with the 'Ninja', So I believe instead of using var, it should this. So the code becomes like this.
function Ninja(name){
this.name = name;
this.changeName = function(name2) {
this.name = name2;
}
}
Hope it helps.
function Ninja(name){
this.name = name;
return {
changeName : function(name2) {
this.name = name2;
}
}
}
In your code changeName is not exposed if you want to access the private data you can try with the above snippet
Another approach to make your function public available would be to first declare it private (Some prefer to use an underscore, like usual in .Net):
function Ninja(name) {
this._name = name;
var _changeName = function(name) {
this._name = name;
}
}
And then export it using return. Some might know this from the classical Java boilerplate Getters and Setters, where fields are declared private by default and Methods make them available:
function Ninja(name) {
this._name = name;
var _changeName = function (name) {
this._name = name;
}
return {
changeName: _changeName,
getName: function () {return _name;}
}
}
...And now, use the object:
var ninja = new Ninja("John");
ninja.changeName("Bob");
console.log(ninja.getName());

How to invoke function inside another function in JavaScript as I've mentioned below

I've a code
function person() {
name = "David";
hello = function() {
console.log("I'm in hello");
};
}
And I want to invoke hello function from outside. How can I achieve it?
Assign hello (and name) to this in person:
function Person() {
this.name = "David";
this.hello = function() {
console.log("I'm in hello");
};
};
Then, you can access the function like this:
var p = new Person();
p.hello();
this assigns the variables to the Person. This prevents the variables from polluting the global scope.
You could also pass parameters to Person:
function Person(name) {
this.name = name;
this.hello = function() {
alert("Hello! I'm " + this.name + '!');
};
};
var p = new Person("Fred");
p.hello();
function person() {
this.name = "David";
this.hello = function() {
console.log("I'm in hello");
};
}
var personObj = new person();
personObj.hello ();
What you can do is that:
function person() {
name = "David";
this.hello = function() {
console.log("I'm in hello");
};
}
var johnny = new person();
johnny.hello();
See this nice article: http://www.phpied.com/3-ways-to-define-a-javascript-class/
function person() {
name = "David";
this.hello = function() {
console.log("I'm in hello");
};
}
var p = new person();
p.hello();
or
function person() {
var obj={};
obj.name = "David";
obj.hello = function() {
console.log("I'm in hello");
};
return obj;
}
var p = person();
p.hello();
This is for your curiosity and clarity :)
You have declared global variables inside a function. Untill you execute the function the global variables will not come into existence and would not be accessible. Once you call the function the globals would be defined and initialized properly and thereafter you can call them from any scope in the javascript.
function person() {
name = "David";
hello = function() {
console.log("I'm in hello");
};
}
Now, in order to call hello from outside without using this or class pattern, you will have to first make a call (method execution) to person method. see this:
either person(); or console.log(person()); but not console.log(person);
and then you can easily call hello();
NOTE: This is for David's understanding purpose. Please do not use
arbitrarily global variables in your javascript.

Constructors in the Module Pattern

When using the module pattern in javascript how should constructors be defined, if at all. I would like my constructor to fit into a standard module pattern and not be global.
Why doesn't something like this work, is it complete and total nonsense?
var HOUSE = function() {
return {
Person: function() {
var self = this;
self.name = "john";
function name() {
return self.name;
}
}
};
}();
var me = new HOUSE.Person();
alert(me.name());
Your code is almost fine. However the function name() was not public but the variable was so you were trying to execute the variable causing an error. Add the function getName onto the object and call that instead:
var HOUSE = function() {
return {
Person: function() {
var self = this;
self.name = "john";
self.getName = function() {
return self.name;
}
}
};
}();
var me = new HOUSE.Person();
alert(me.getName());
http://jsfiddle.net/8nSbP/
Using var and function foo() {} (the latter as a declaration, which means "just" function foo() {} without assigning it), create local symbols. So, the function is not available outside the constructor.
Whatever you want to expose (make public), you should assign to this (or self since you defined self = this):
self.getName = function() {
return self.name;
};
Note that you already used name, so I gave function another name. If you wanted to make the name string local, and expose the function, then they can have the same name since there is no conflict. E.g.:
var name = "john";
self.name = function() {
return name;
};
You need to bring the method out, and attach it to the Person prototype. But when you do, you'll have a name property, and a name method, which won't work, so consider renaming the latter
HOUSE.Person.prototype.getName = function(){
return this.name;
}
OR, you could just attach it to this, and make getName a privileged method:
Person: function() {
this.name = "john";
this.getName = function() {
return this.name;
}
}

how do i namespace pseudo-classical javascript

I have some simple OO code I've written that I'm playing with:
//define a constructor function
function person(name, sex) {
this.name = name;
this.sex = sex;
}
//now define some instance methods
person.prototype.returnName = function() {
alert(this.name);
}
person.prototype.returnSex = function() {
return this.sex;
}
person.prototype.talk = function(sentence) {
return this.name + ' says ' + sentence;
}
//another constructor
function worker(name, sex, job, skills) {
this.name = name;
this.sex = sex;
this.job = job;
this.skills = skills;
}
//now for some inheritance - inherit only the reusable methods in the person prototype
//Use a temporary constructor to stop any child overwriting the parent prototype
var f = function() {};
f.prototype = person.prototype;
worker.prototype = new f();
worker.prototype.constructor = worker;
var person = new person('james', 'male');
person.returnName();
var hrTeamMember = new worker('kate', 'female', 'human resources', 'talking');
hrTeamMember.returnName();
alert(hrTeamMember.talk('I like to take a lot'));
Now this is all well and good. But I'm confused. I want to include namespacing as part of my code writing practice. How can I namespace the above code. As it is now I have 2 functions defined in the global namespace.
The only way I can think to do this is to switch to object literal syntax. But then how do I implement the pseudo-classical style above with object literals.
You could for example do following:
var YourObject;
if (!YourObject) {
YourObject = {};
YourObject.Person = function(name, sex) {
// ...
}
YourObject.Person.prototype.returnName = function() {
// ...
}
// ...
}
You don't have to use object literals, at least, not exclusively.
Decide on the single global symbol you'd like to use.
Do all your declaration work in an anonymous function, and explicitly attach "public" methods as desired to your global object:
(function(global) {
// all that stuff
global.elduderino = {};
global.elduderino.person = person;
global.elduderino.worker = worker;
})(this);
I may not be completely understanding the nuances of your issue here, but the point I'm trying to make is that Javascript makes it possible for you to start with your symbols being "hidden" as locals in a function, but they can be selectively "exported" in various ways.

Categories

Resources