I'm learning JavaScript, and was wondering if it was possible to define getters and setters in object functions.
The main difference is the way of calling it, if defined as getFullName = function(), I should call the method as myObj.getFullName(), however, as for arrays, a getter allows for it to be called as a simple property myObj.fullName (without parenthesis).
As I saw in MDN reference (http://mzl.la/1CIUuIw), it is easily done in Object Literals:
var obj = {
get var(){
return "something";
}
}
However, I can't do it on object functions like so:
function obj(name, lname){
this.name = name;
this.lastName = lname;
get fullName(){
return this.name + " " + this.lastName;
}
}
Getting a "Unexpected identifier" error...
As get XX(){} is used for var obj = {}; But here you use a constructor to create new object. So you should use MDN - Object.defineProperty().
And if you want the fullName apply on all object create from obj, apply it on its prototype.
function obj(name, lname){
this.name = name;
this.lastName = lname;
}
Object.defineProperty(obj.prototype, 'fullName', {
get : function() {
return this.name + " " + this.lastName;
}
});
var aObj = new obj("first", 'lastN');
console.log(aObj.fullName);
UPDATE:
If you want a more straight way, and not scared to try new things, then ES2015's class notation can do it more easily:
// ES2015 - class
class obj {
constructor(name, lname) {
this.name = name;
this.lname = lname;
}
// Define getter method for fullName
get fullName() {
return this.name + " " + this.lastName;
}
}
var aObj = new obj('Billy', 'Hallow');
console.log(aObj.fullName);
Currently most browsers don't support that, if you want to use this in your site, you need to use js compilers like Babel to transpile it from ES2015 to ES5.
Babel also provide a playground for those who has interest in ES2015, you can copy above codes to the playground to see how it works.
Javascript uses prototype inheritance and its functions start with function keyword. By convention, object's first character is capitalised.
function Obj(name, lname){
this.name = name;
this.lastName = lname;
}
Obj.prototype.get = function() {
return this.name + " " + this.lastName;
}
var person = new Obj('luke', 'lim');
console.log(person.get()); // 'luke lim'
Just make a variable and assign the function to it.
function obj(name, lname){
this.name = name;
this.lastName = lname;
this.fullName = function(){
return this.name + " " + this.lastName;
};
}
Try to read something about Javascript closure if you want to know more about it.
Furthermore, this link, Javascript methods, is explaining EXACTLY what you need, which is adding a method to an object. And a getter is traditionally just a method.
function obj(name, lname){
this.name = name;
this.lastName = lname;
}
obj.prototype.getfullName = function(){
return this.name + " " + this.lastName;
}
use this as
a = new obj("My","Name");
a.getfullName() //"My Name"
Related
Suppose that I have a javascript constructor:
function Person(name) {
this.name = name;
this.hello = function () { return "It's a-me, " + name + "!"; };
}
the Person "type" has a convenient method, hello that I would like to re-use on another type Student. I would like for a Student to have the following structure:
function Student(name) {
this.name = name;
this.hello = function () { return "It's a-me, " + name + "!"; };
this.books = [];
}
One option is to use the code for Student as-is above. This is sub-optimal for the usual reasons, such as that if I want it to mirror the Person type, then I have to manually keep their code in sync. Anyway, this is not good.
A second option (from this answer) is to do something like:
function Student(name) {
Person.call(this, name);
this.books = [];
}
When I mario = new Student("mario") I get the following:
Object { name: "mario", hello: hello(), books: [] }
I've successfully achieved the inheritance that I wanted, but this has the unfortunate property of placing all of the desired properties into my object. Notably, for example, there is a "hello" property on mario. It would be nice if that "hello" property could be looked up in the prototype chain.
How can I neatly create a prototype chain given the relevant object constructors?
When you create an object with new, the this value of your constructor function is set to the object, and that object's prototype is set to the prototype of the constructor Function being called.
That's why your properties are currently being added to the created object.
function Student {
this.name = name
}
const student = new Student('John')
// is (almost) equivalent to the following
const student = {}
student.name = 'John'
But if you want to add properties to the prototype instead, so that you can use inheritance, then in ES5 Javascript you can do so by assigning properties directly to the prototype of your constructor function.
function Person(name) {
this.name = name;
}
// Person is a function
// Its prototype is an instance of Object, and it has no properties
// i.e. something like Person.prototype = new Object()
Person.prototype.hello = function() {
return 'It is I, ' + this.name
}
// Now Person.prototype has one property, "hello", which is a function.
function Student(name) {
Person.call(this, name)
this.books = [];
}
// Student is a function
// Its prototype is also an instance of Object with no properties
// the following is the magic line
Student.prototype = Object.create(Person.prototype)
// We replace the prototype of the Student function with a new object, but
// Object.create() allows us to set the prototype to an existing object, in this case Person.prototype,
// Person.prototype is itself an instance of Object, and we previously
// added the "hello" function to it as a property.
const student = new Student('John')
// So what happens here?
// First a new object is created, and its prototype is set to Student.prototype
// Then we call Person.call(this)
// Which executes the body of the Person function
// So you get the properties on the object itself through the body of the Person and Student functions
// And you get the shared functionality through the prototype chain of instance -> Student.prototype -> Person.prototype -> Object.prototype
Hope that helps!
You can use prototyping method or class sugar method as you want.
Here is a simple example :
function Student(name) {
this.name = name;
this.books = [];
}
Student.prototype.hello = function(){
return "It's a-me, " + this.name + "!";
}
Student.prototype.addBook = function(book){
this.books.push(book);
}
Student.prototype.getBooks = function(){
return this.books;
}
let mario = new Student("Mario");
console.log(mario.hello());
mario.addBook("prototyping");
mario.addBook("chain");
console.log(mario.getBooks());
class Person {
constructor(name) {
this.name = name;
this.books = [];
}
hello(){
return "It's a-me, " + this.name + "!";
}
addBook(book){
this.books.push(book);
}
getBooks(){
return this.books;
}
}
let luigi = new Person("Luigi");
console.log(luigi.hello());
luigi.addBook("classSugar");
luigi.addBook("classType");
console.log(luigi.getBooks());
For longer chains use Object.assign, here is an example of making a GradStudent that is both a Student and a Person and has the personality of a Comedian and also has the properties and methods of a 4th class GameCharacter:
(function() {
//Person
function Person(name) {
this.name = name;
this.helloString = "Hello my name is "
}
Person.prototype.name = "Bob";
Person.prototype.hello = function() {
return this.helloString + this.name;
};
//Student
function Student(name, books) {
Person.call(this, name);
this.books = books;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.books = ["math","reading"];
//Comedian
function Comedian(name) {
Person.call(this,name);
};
Comedian.prototype = Object.create(Person.prototype);
Comedian.prototype.constructor = Comedian;
Comedian.prototype.hello = function() {
return "I don't know what my parents where thinking when they name me Squat, just kidding, my name is " + this.name;
};
//GameCharacter
function GameCharacter(power) {
this.power = power;
};
GameCharacter.prototype = new Object();
GameCharacter.prototype.constructor = GameCharacter;
GameCharacter.prototype.gainPower = function(power) {
this.power += ", "+power;
};
GameCharacter.prototype.statePower = function() {
return this.power;
};
//GradStudent
function GradStudent(name, books, degree) {
Comedian.call(this, name);
Student.call(this,name,books);
GameCharacter.call(this, "jumping");
this.degree = degree;
this.gainPower("flying");
}
GradStudent.prototype = Object.create(Student.prototype);
Object.assign(GradStudent.prototype, Comedian.prototype, GameCharacter.prototype);
GradStudent.prototype.constructor = GradStudent;
var gradStudent = new GradStudent("Bill",["C", "C++", "JavaScript"], "B.S.");
console.log(gradStudent.hello() + " I have a " + gradStudent.degree +" I am studying " + gradStudent.books.toString() + ". \n In a game I play my power's are "+ gradStudent.statePower() + ". \n Is gradStudent also a Student? " + (gradStudent instanceof Student) + "" );
var otherStudent = new Student("Jennifer" ,["english", "science"]);
console.log(gradStudent.books.toString() + " " + otherStudent.books.toString());
})();
GradStudent is an instance of Student, it's a type of Student, and can also do all the things Comedian and GameCharacter does. The value of Object.assign is that kind of multiple inheritance.
I can accomplish such a thing with the following:
function Student(name) {
Object.setPrototypeOf(this, new Person(name));
this.books = [];
}
However, I'm not familiar enough with javascript to know what possible problems might arise with this solution. Coming from other OO style languages, it feels weird for the prototype of mario to be an actual instance of a Person, but I suppose everything in js is an instance, in some sense, so this might just be bias on my part.
Please find the below code for more information.
var person = {
firstname:"john",
lastname:"doe",
greet: function(){
return "hello " + this.firstname + " " + this.lastname;
}
}
console.log(person.greet());
How can I make above object literal function greet() dymanic? Like I can pass params values for example person.greet('jessie','jay') will return hello jessie jay
Is it better to use constructor method (instances) in order to make function dynamic and reusable? I found that object literal is just to organize code.
I'll suggest you to use Constructor function. This pattern is called as Factory pattern. The function here acts as class and for each person a new object can be created.
function Person(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
Person.prototype.greet = function () {
return 'Hello ' + this.firstname + ' ' + this.lastname;
};
var jon = new Person('Jon', 'Skeet');
var tushar = new Person('Tushar', 'Jadhav');
console.log(jon.greet()); // Hello Jon Skeet
console.log(tushar.greet()); // Hello Tushar Jadhav
First, you should think about what person and greet actually is or should be. If person is an object and greet a method that operates on the data of that object, the way you've written person is fine.
If you consider person to be some kind of namespace or module you will use to organize your code, you will write greet as a pure function that doesn't depend on and modify any variables out of its scope. In this case you won't have person instance data as firstname and lastname on person.
var person = {
greet: function(person){
return "hello " + person.firstName+ " " + person.lastName;
}
};
var jenny = { firstName : 'Jennifer', lastName : 'IdowntKnow' };
person.greet(jenny);
A combination of both will be very confusing in this case
var person = {
firstname:"john",
lastname:"doe",
greet: function(firstName, lastName){
/* .. */
}
};
person.greet('Jennifer', 'IdowntKnow');
// hmm, what happens here? Person switched to Jennifer now? What about john? weird code...
The question if you should use a constructor function is more about performance or if you need features like prototypal inheritance.
greet: function(fname, lname){
return "hello " +fname + " " + lname;
}
if you also want to update firstname and lastname
greet: function(fname, lname){
this.firstname =fname;
this.latname =lname;
return "hello " +fname + " " + lname;
}
i am a newbie to js.
i am trying to use constructor function to create an object.
here is my code
function player(name,age,rank)
{
this.name=name;
this.age=age;
this.rank=rank;
this.sayEverything=function()
{
return "The name of the player is " + this.name + "the age is " + this.age + "the rank is " + this.rank;
}
Now i am adding a new property like this
player.matchReady=true;
now i create an object like this
var kaka=new player("kaka",22,3,false);
And when i write this
document.write('kaka is match ready-->' + kaka.matchReady);
it gives me this output
kaka is match ready-->undefined
Why is it giving me undefined??
haven't i added a new property correctly??Please tell me.
Thanks.
Instead of player.matchReady=true;
Do, player.prototype.matchReady = true;
This way all players will have match ready default on true;
also you might want to put your function into the prototype.
player.prototype.sayEverything=function()
{
return "The name of the player is " + this.name + "the age is " + this.age + "the rank is " + this.rank;
}
You can regard prototype as the scaffolding on which you outline all properties and functions an object should have when it's instantiated. All these default values will be the same for all objects.
When you add functions within functions all these functions get duplicated in memory when you instantiate a new object.
When possible and when there is no need for scoping, try to add generic functions like your sayEverything()(please rename that to toString() to keep in line with convention) to the prototype.
That way all the player objects can use the same function. Which is more memory efficient.
You cannot add a property to a class. You can always add the property as its prototype.
like this:
function player(name, age, rank) {
this.name = name;
this.age = age;
this.rank = rank;
this.sayEverything = function () {
return "The name of the player is " + this.name + "the age is " + this.age + "the rank is " + this.rank;
}
}
player.prototype.matchReady = true;
var kaka = new player("kaka", 22, 3, false);
alert('kaka is match ready-->' + kaka.matchReady);
working example: jsfiddle
Blog on prototype
If you add it to the prototype, all player will have the field.
player.prototype.matchReady = true;
If you only want a specific player to have the field, add it to that player variable:
var kaka = new player("kaka",22,3,false);
kaka.matchReady = true;// kaka has to come first
In the below example you can see what is private ,public,static and privileged variable or method .When ever you write property on Method itself like static variable,that variable wont be available for the instances.
Also whenever you are writing constructor function you should follow the Naming convention to help you differentiate from other function
/ Constructor
function Player(name) {
// Private
var dob= "17/04/1986";
// Privileged
this.getDOB = function () {
return dob;
};
// Public
this.name = name;
}
// Public
Player.prototype.getName = function () {
return this.name;
};
// Static property
Player.town = "South Park";
So the idea is to create a class Animal and the set properties to it as a new object
Here is what I have:
var name;
var type;
function Animal(name,type){
this.type = type,
this.name = name,
toString = function(){return this.name + "is a " + this.type;}
};
var cat = new Animal('Max','cat');
cat.type;
everytime I run it - I seem to fail at the toString part? Pretty new and trying to learn this - is there something I am missing?
You don't need to declare those top variables, the arguments should be local to the function. The syntax is wrong too, you should use semicolons, not commas, and toString becomes a global variable since you forgot to use var.
What you want is this.toString so this works inside and refers to the instance, or better yet, create a method on the prototype so it's re-usable for all instances of Animal:
function Animal(name,type) {
this.type = type;
this.name = name;
}
Animal.prototype.toString = function() {
return this.name + "is a " + this.type;
};
function Animal(name, type) {
this.type = type;
this.name = name;
};
Animal.prototype.toString = function() {
return this.name + "is a " + this.type;
}
var cat = new Animal('Max', 'cat');
console.log(cat); // Prints "Max is a cat"
Is this a good/safe cross-browser way to implement method overriding in JavaScript? :
function Person(firstName, lastName)
{
this.firstName = firstName;
this.lastName = lastName;
};
Person.prototype.sayHi = function()
{
return "Hi, my name is " + this.firstName;
};
function Employee(firstName, lastName, position)
{
Person.call(this, firstName, lastName);
this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.sayHi = function()
{
return this.constructor.prototype.sayHi() + " I'm a " + this.position;
}
I could also write:
Employee.prototype.sayHi = function()
{
return Person.prototype.sayHi() + " I'm a " + this.position;
}
but with this solution I'm refering to direct method, or
Employee.prototype.sayHi = function()
{
return this.__proto__.sayHi() + " I'm a " + this.position;
}
but this one is awful and not crossbrowser.
EDIT: I assumed Object.create is crossbrowser as I can use a shim
You should not rely on the constructor property of the prototype to call parent functions because normally, that property should point to the children constructor.
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
There are a few other ways to access parent functions safely, like referring to the parent prototype directly like you are trying to do in your second example, however there's something wrong with the way you are doing it.
If you call sayHi without using call or apply, this will point to Person.prototype during the function call and that's not what you want.
You should call sayHi by setting the context object to the current employee instance, like this:
Employee.prototype.sayHi = function() {
return Person.prototype.sayHi.call(this) + " I'm a " + this.position;
};
Another way of doing this would be to store a reference to the parent prototype in the children prototype.
Employee.prototype.super = Person.prototoype;
Employee.prototype.sayHi = function() {
return this.super.sayHi.call(this) + " I'm a " + this.position;
};
Another interesting approach I've seen is to wrap every function of the children prototype in a function that dynamically sets a reference to the parent function on the object instance, so that you can only use this.parent() to call the function. However I would not recommend this solution since it will reduce performances and increase memory usage.
I have created a jsFiddle to demonstrate that concept.
No.
Employee.prototype = Object.create(Person.prototype);
Object.create is not supported by older browsers, but you can shim it.
Employee.prototype.sayHi = function() {
return this.constructor.prototype.sayHi() + " I'm a " + this.position;
}
I wouldn't use that. You expect this.constructor to be the Person from which you inherited from, but that might not be the case. Actually it would be good practise to set the Employee.prototype.constructor = Employee, which would cause recursion with a stack overflow to your method.
Instead, you should explicitly refer to the function you want to use:
return Person.prototype.sayHi.call(this) + " I'm a " + this.position;
If you want it dynamically, you'd use
return Object.getPrototypeOf(Employee.prototype).sayHi.call(this) + " I'm a " + this.position;
but notice that Object.getPrototypeOf is not supported in older browsers. So if you need a cross-browser and DRY way, use the module pattern:
(function(proto, super) {
proto.sayHi = function() {
return super.sayHi.call(this) + " I'm a " + this.position;
};
…
})(Employee.prototype, Person.prototype);
or the revealing prototype pattern:
Employee.prototype = (function(super) {
var proto = Object.create(super);
proto.sayHi = function() {
return super.sayHi.call(this) + " I'm a " + this.position;
};
…
return proto;
})(Person.prototype);