In an OOP way, I am defining a Person "class" as follows:
var Person = {
name: '',
age: 32,
gender: 'male',
interests: ['music', 'skiing'],
bio: function() {
alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
},
greeting: function() {
alert('Hi! I\'m ' + this.name + '.');
}
};
Now, I am instantiating the above class.
var person1= Object.create(Person);
person1.name = 'personname';
person1.greeting();
How can I mimic a constructor so that when Object.create(Person) creates a new object, the constructor code is automatically computed?
You would wrap up the code in a function, and call it there. Object.create will establish a relationship with the prototype, but won't call any additional code automatically.
function person(name) {
var person1 = Object.create(Person);
person1.name = name;
return person1;
}
person('personname').greeting();
You should also avoid uppercasing the first letter of variables unless they are functions which should be called using new. This is a naming convention used only for constructor functions.
You could make an real class for use with new.
var Person = function () {
var Person = function () {
this.name = ['', ''];
this.age = 32;
this.gender = 'male';
this.interests = ['music', 'skiing'];
};
Person.prototype.bio = function() {
return this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.';
};
Person.prototype.greeting = function() {
return 'Hi! I\'m ' + this.name + '.';
};
return Person;
}();
var p1 = new Person;
p1.name = ['Tom', 'Sawyer'];
console.log(p1.bio());
console.log(p1);
var Person = function(name) {
this.name = name || '';
this.age = 32;
this.gender = 'male';
this.interests = ['music', 'skiing'];
this.bio = function() {
alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
};
this.greeting = function() {
alert('Hi! I\'m ' + this.name + '.');
};
};
var person1= new Person('personname');
person1.greeting();
Related
var peopleFactory = function(name, age, height) {
var temp = {};
this.name = name;
this.age = age;
this.height = height;
temp.printPerson = function() {
console.log(this.name + '' + this.age + '' + this.height);
document.write(this.name + '' + this.age + '' + this.height);
};
return temp;
};
var person1 = peopleFactory('tanmay', 27, 5.11);
var person2 = peopleFactory('chinmay', 37, 5.12);
person1.printPerson();
person2.printPerson();
Not sure but here you go. Just make it a class.
class peopleFactory {
constructor(name, age, height) {
this.name = name;
this.age = age;
this.height = height;
}
printPerson() {
return this.name + ' ' + this.age + ' ' + this.height;
};
};
var person1 = new peopleFactory('tanmay', 27, 5.11);
console.log(person1.printPerson())
You should not be using this in your factory as it's a reference to the global object (unless you want to call your factory with the new keyword. But then, it wouldn't be a factory anymore).
Instead, you could be using another local object where you would store your object's private data. By doing that, your printPerson() function becomes a closure and can access data inside that local object and will be able to print it once it's invoked.
var peopleFactory = function(name, age, height) {
var temp = {}, instance = {};
temp.name = name;
temp.age = age;
temp.height = height;
instance.printPerson = function() {
console.log(temp.name + ' ' + temp.age + ' ' + temp.height);
document.write('<br/>' + temp.name + ' ' + temp.age + ' ' + temp.height);
};
return instance;
};
var person1 = peopleFactory('tanmay', 27, 5.11);
var person2 = peopleFactory('chinmay', 37, 5.12);
person1.printPerson();
person2.printPerson();
I have this code snippet from MDN
I then added a bit of my own code to attach a jQuery click event to a paragraph.
Maybe it is best to show the example:
function Person(first, last, age, gender, interests) {
this.name = {
'first': first,
'last' : last
};
this.age = age;
this.gen = gender;
this.int = interests;
this.nationality = "English";
this.bio = function() {
alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.int[0] + ' and ' + this.int[1] + '.');
};
this.greeting = function() {
alert('Hi! I\'m ' + this.name.first + '.');
};
this.tt = function() {
alert('Hi! I\'m ' + this.gen + '.');
};
this.init= function() {
$("p").click(function(){
alert('Hi!'); //works fine
alert('Hi! I\'m ' + this.name.first + '.');//obj.html:34 Uncaught TypeError: Cannot read property 'first' of undefined
});
};
this.init(); //Bind to the P tag using jQuery click event
}
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
console.log(Person);
person1.bio();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>My first paragraph.</p>
So when I click on the P element I get the alert Hi! followed by the uncaught error message.
How do I get the second alert to read, "Hi! I'm Bob"
There are a few ways to solve your problem. this keyword in JavaScript is tricky. The core of your problem is that the this is not what you think it is. See How does the "this" keyword work? for more details.
1) Cache the this into a variable in pervious scope.
this.init = function () {
var self = this;
$("p").click(function () {
alert('Hi!');
alert('Hi! I\'m ' + self.name.first + '.');
});
};
2) bind this into the function that's being invoked
this.init = function () {
var handleClick = function () {
alert('Hi!');
alert('Hi! I\'m ' + self.name.first + '.');
};
handleClick = handleClick.bind(this);
$("p").click(handleClick);
};
If you wish to retain the reference to the Person object, then you need to bind the jQuery callback function with the thisBinding.
this.init= function() {
$("p").click(function(){
alert('Hi!'); //works fine
alert('Hi! I\'m ' + this.name.first + '.');
}.bind(this));//binding this prevents the error
};
Another way to do this is to just declare a variable name outside the jquery function and use it inside the function
this.init = function() {
var name = this.name;
$("p").click(function(){
alert('Hi!');
alert('Hi! I\'m ' + name.first + '.');
});
};
You need to bind this to the anonymous function you passed in jquery click() function.
function Person(first, last, age, gender, interests) {
this.name = {
'first': first,
'last' : last
};
this.age = age;
this.gen = gender;
this.int = interests;
this.nationality = "English";
this.bio = function() {
alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.int[0] + ' and ' + this.int[1] + '.');
};
this.greeting = function() {
alert('Hi! I\'m ' + this.name.first + '.');
};
this.tt = function() {
alert('Hi! I\'m ' + this.gen + '.');
};
this.init= function() {
$("p").click(function(){
alert('Hi!'); //works fine
alert('Hi! I\'m ' + this.name.first + '.');
}.bind(this));
};
this.init(); //Bind to the P tag using jQuery click event
}
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
console.log(Person);
person1.bio();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>My first paragraph.</p>
Be careful when using this for variables. This, in your code refers to thePersoninstance. As soon as you create a new functionthisno longer references thePersonfunction, but thethis.initfunction, thusPerson` no longer exists in this context.
Rather user var name... when using variables, then you will be able to reference it in another context or function:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<p>My first paragraph.</p>
<script>
function Person(first, last, age, gender, interests) {
var name = {
'first': first,
'last' : last
};
var age = age;
var gen = gender;
var int = interests;
var nationality = "English";
this.bio = function() {
alert(name.first + ' ' + name.last + ' is ' + age + ' years old. He likes ' + int[0] + ' and ' + int[1] + '.');
};
this.greeting = function() {
alert('Hi! I\'m ' + name.first + '.');
};
this.tt = function() {
alert('Hi! I\'m ' + gen + '.');
};
this.init= function() {
$("p").click(function(){
alert('Hi!'); //works fine
alert('Hi! I\'m ' + name.first + '.');//obj.html:34 Uncaught TypeError: Cannot read property 'first' of undefined
});
};
this.init(); //Bind to the P tag using jQuery click event
}
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
console.log(Person);
person1.bio();
</script>
</body>
</html>
I have this object:
function Boy(n,s,a)
{
this.name = n;
this.surname = s;
this.age = a;
this.getInfo = function(){
return this.name + ' ' + this.surname + ' (' + this.age + ')';
}
}
I want to do something like this:
{{ boy.getInfo() }}
and not like this:
{{ boy.name }} {{ boy.surname }} ({{boy.age}})
is it possible?
there are some tricks for doing something similar?
Absolutely! You can create an object and shove it into $scope just like anything else.
var NameController = function ($scope) {
$scope.boy = new Boy("Foo", "Bar", 32);
};
NameController.$inject = ['$scope'];
app.controller("NameController", NameController);
And then bind it in the UI just like so:
<h3>{{boy.getInfo()}}</h3>
Here is an example of binding to all three properties and seeing the result of the function: http://jsfiddle.net/jwcarroll/Pb3Cu/
You can bind $scope functions normally
function MyController($scope){
$scope.myfunc = function(){
return "test";
}
}
and then, in the view
{{ myfunc() }}
You can do something like:
function Boy(n,s,a)
{
this.name = n;
this.surname = s;
this.age = a;
this.getInfo = function(){
return this.name + ' ' + this.surname + ' (' + this.age + ')';
}
}
var boy = new Boy(n, s, a);
$scope.boy = function(){
return boy.getInfo();
}
And in you template just bind {{boy()}}.
Trying to understand prototypes. I'm playing around in Chrome's console and was hoping someone can point me to why this is happening.
function Gadget(name, color) {
this.name = name;
this.color = color;
this.whatAreYou = function(){
return 'I am a ' + this.color + ' ' + this.name;
}
}
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
Gadget.prototype.getInfo = function() {
return 'Rating: ' + this.rating + ', price: ' + this.price;
};
var newtoy = new Gadget('webcam', 'black');
newtoy.constructor.prototype
Gadget {price: 100, rating: 3, getInfo: function} //Expected
Now if I try the following, prototype does not have the expected results.
function Gadget(name, color) {
this.name = name;
this.color = color;
this.whatAreYou = function(){
return 'I am a ' + this.color + ' ' + this.name;
}
}
Gadget.prototype = {
price: 100,
rating: 3,
getInfo: function() {
return 'Rating: ' + this.rating + ', price: ' + this.price;
}
};
var newtoy = new Gadget('webcam', 'black');
newtoy.constructor.prototype
Object {} //Empty Object!!!!!???
jsFiddle Demo
This is because you overwrote the prototype instead of extending it when you did this:
Gadget.prototype =
It is common when overwriting it, to make a facade of the constructor like this:
Gadget.prototype = {
constructor : Gadget
}
So for your exact situation:
Gadget.prototype = {
constructor : Gadget,
price: 100,
rating: 3,
getInfo: function() {
return 'Rating: ' + this.rating + ', price: ' + this.price;
}
};
Prototype is initially a special typed object. When you assign the prototype with a new object (the curly braces are short hand for a new object) you lose the special prototype object.
See How does JavaScript .prototype work? for a deeper explanation.
I asked a question here:
Extending javascript literal object
which was solved because I forgot return. Now I didn't forget return and I got undefined again, why ?
<script>
var secretAgent = (function(){
var person = {},
firstName = "James",
lastName = "Bond";
person.WhoAreYou = function() {
alert("My name is " + this.lastName + ", " + this.firstName + " " + this.lastName);
};
return person;
})();
</script>
<script>
secretAgent.WhoAreYou();
</script>
Update: why mine doesn't work whereas I think I did the same thing as the one below that works:
http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/
//Revealing Module Pattern (Public & Private)
var skillet = (function() {
var pub = {},
//Private property
amountOfGrease = "1 Cup";
//Public property
pub.ingredient = "Bacon Strips";
//Public method
pub.fry = function() {
console.log( "Frying " + pub.ingredient );
};
//Private method
function privateWay() {
//Do something...
}
//Return just the public parts
return pub;
}());
//Public Properties
console.log( skillet.ingredient ); //Bacon Strips
//Public Methods
skillet.fry();
//Adding a public property to a Module
skillet.quantity = 12;
console.log( skillet.quantity ); //12
//Adding a public method to a Module
skillet.toString = function() {
console.log( skillet.quantity + " " +
skillet.ingredient + " & " +
amountOfGrease + " of Grease" );
};
try {
//Would have been successful,
//but can't access private variable
skillet.toString();
} catch( e ) {
console.log( e.message ); //amountOfGrease is not defined
}
You need to declare those properties on the literal itself (rather than separate unrelated variables), like this:
var secretAgent = (function(){
var person = { firstName: "James", lastName: "Bond" };
person.WhoAreYou = function() {
alert("My name is " + this.lastName + ", " + this.firstName + " " + this.lastName);
};
return person;
})();
You can test it out here.
There are two problems here, as I see it.
You did forget the return, again. :-) The WhoAreYou function doesn't actually return anything, it just alerts. Hence secretAgent.WhoAreYou() returns undefined too.
The alert shows "My name is undefined, undefined undefined". This is because of the scope of the variables used. You assign the WhoAreYou to person, and within the body you reference this.lastName. The this here refers to the person variable, and as you can see this object does not have a lastName property.
There are two ways then that you can fix the latter issue. Firstly, by adding the name variables to the person object:
var secretAgent = (function(){
var person = {};
person.firstName = "James";
person.lastName = "Bond";
person.WhoAreYou = function() {
alert("My name is " + this.lastName + ", " + this.firstName + " " + this.lastName);
};
return person;
}
)();
// Although the first three lines would be more natural as:
var person = { firstname: "James", lastName: "Bond" };
Secondly, you can instead choose to drop the this reference, which will instead refer to the local variables you just defined:
var secretAgent = (function(){
var person = {},
firstName = "James",
lastName = "Bond";
person.WhoAreYou = function() {
alert("My name is " + lastName + ", " + firstName + " " + lastName);
};
return person;
}
)();
You'll of course need to add appropriate returns to the WhoAreYou function in both examples.
Remove "this" from the variables since you are setting them as a var with in the anonymous function, using this points to that function and not "Person" which is where you are now calling them.
<script>
var secretAgent = (function(){
var person = {},
firstName = "James",
lastName = "Bond";
person.WhoAreYou = function() {
alert("My name is " + lastName + ", " + firstName + " " + lastName);
};
return person;
}
)();
</script>
<script>
secretAgent.WhoAreYou();
</script>
example here: JSFiddle
Why not just:
var secretAgent = {
firstName: "James",
lastName: "Bond",
whoAreYou: function() {
alert("My name is " + this.lastName + ", " +
this.firstName + " " + this.lastName);
}
};
The way you defined firstName and lastName are not fields to object person itself. But they are upper values to function WhoAreYou. So you could write the function like this:
person.WhoAreYou = function() {
alert("My name is " + this.lastName + ", " + this.firstName + " " + this.lastName);
};
Its like if those were private variables to the function. The alternative is declaring as filelds to the object itself like this:
var person = {
firstName: "James",
lastName: "Bond",
};
The the method whould work as you wrote it.
The variable this is person in your case, also firstName and lastName are defined as local variables, but not as properties of the person, so you can just access them within the anonymous function by names:
var secretAgent = (function(){
var person = {},
firstName = "James",
lastName = "Bond";
person.WhoAreYou = function() {
alert("My name is " + lastName + ", " + firstName + " " +lastName);
};
return person;
})();
secretAgent.WhoAreYou();