overwrite object property Javascript - javascript

I basically having hard times understanding why I cannot overwrite an object property when using inheritance from another object, it goes like this.
var Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
};
Object.defineProperties(Person.prototype, {
sayHi : {
value :function() {
return "Hi there";
},
enumerable : true,
writable : true
},
fullName : {
get : function() {
return this.firstName + " " + this.lastName;
},
enumerable : true
}
});
var createEmployee = function(firstName, lastName, ocupation) {
var employee = new Person(firstName, lastName);
employee.ocupation = ocupation;
Object.defineProperty(employee, "sayHi", {
sayHi : {
value : function() {
return "Hey I am " + this.firstName;
}
}
});
return employee;
};
var janeDoe = createEmployee('Jane', 'Doe', 'Actress');
So, accoding to what I understand, I should overwrite the sayHi property on the employee object, however, I get it as undefined.
Could please some1 show me money?
here is the jsfiddle
Best Regards.

You could use the outdated Object.defineProperty() or the Object.assign(). However, there's a cleaner, more modern solution to this.
Simply do:
objectName = {...objectName, property: "newvalue"};
// or
objectName = {property: "newvalue", ...objectName};
the difference between the two is that the first will overwrite the property named property, while the second will create a new property called property and assign a value, however, it won't overwrite it if it already exists.
Take a look at JS spread syntax for more info.
Such could also be done for setting your prototype:
Person.prototype = {...Person.prototype, sayHi: _=>"Hi there!"};

Just realized the answer I gave was bad.
You don't need the name inside the object there.
Object.defineProperty(employee, "sayHi", {
sayHi : {//<- don't need this.
value : function() {
return "Hey I am " + this.firstName;
}
}//<- or this.
});

Try this:
Object.defineProperty(employee, "sayHi", {
value: "Hey I am " + employee.firstName
});
Also, Mozilla's explanation on Object.defineProperty() is quite excellent, you should check it out.

Related

Passing parameters as arguments in OOP

I have just started to learn OOP. I am still trying to understand how everything works. I am trying to make a new function that will basically allow me to create a new object by passing the parameters of said class.
Is this even possible, and if so what am I doing wrong?
As stated, still learning so any advice will be appreciated.
class Person {
constructor(name) {
this.persName = name;
}
myName() {
return "My name is " + this.persName;
}
}
function getPers(_perName, fullName) {
_personName = new Person(fullName);
}
$(document).ready(function() {
getPers(John, "John Doe");
});
You can follow the following exapmle. Please note there is not much logic init. The example is just to show you how OOP can work. Of cause, there are many other and better ways to got with that, but for the first try, it should be good to use.
class Person {
//declare the constructor with required name values and optional age value
constructor(firstName, lastName, age = 0) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
//declare a typically setter, e.g. for age
setAge(age) {
this.age = age;
}
//declare a getter for the person with age
getPerson() {
return this.firstName + ' ' + this.lastName + ' is ' + this.age + ' years old.';
}
}
//here you got with some function within you need to define a new person
function getCreatedPerson(firstName, lastName, age = 0) {
//define the person with required firstname and lastname
const person = new Person(firstName, lastName);
//use the setter to set age of person
person.setAge(age);
//return the person by using the person getter
return person.getPerson();
}
//here you can call the createdPerson function
$(document).ready(function() {
console.log(getCreatedPerson('John', 'Doe', 32));
});
Hope it helps a bit to understand how it could work.
Yes, you can take the fullname as a parameter to your function and pass it through to the OOP method or constructor you're calling.
But you can't take a "reference to a variable" as an argument, like you tried with _perName/_personName. Instead, use the return keyword to return the created object:
function createPerson(fullName) {
return new Person(fullName);
}
$(document).ready(function() {
var john = createPerson("John Doe");
… // use john
});

Javascript doesn't return properly?

I am in the process of learning Javascript and came across the apply function. I thought I could assign my apply value to a variable and then print out the contents of the variable. However, I seem to get undefined and I'm not sure why this is happening...
var thisObj = {
fullName: 'test',
setName: function(firstName, lastName) {
this.fullName = firstName + " " + lastName
}
}
function getInput(firstName, lastName, callBack, createdObj) {
return callBack.apply(createdObj, [firstName, lastName]);
}
var thisObjectInstantiated = getInput("Michael", "Jackson", thisObj.setName, thisObj);
console.log(thisObjectInstantiated); // Why is this undefined?
I noticed also if I change the print to do something like this, my name is properly defined.
var thisObjectInstantiated = getInput("Michael", "Jackson", thisObj.setName, thisObj);
console.log(thisObj.fullName); // This is defined properly!
How come I can't just store the results of the apply within the thisObjectInstantiated variable? Thanks.
You are calling the getInput function, that is calling the setName function, that doesnt return nothing, so thisObjectInstantiated is receiving... nothing!
You would probably want to change your code like this:
var thisObj = {
fullName: 'test',
setName: function(firstName, lastName) {
this.fullName = firstName + " " + lastName;
return this;
}
}
You are assigning the result of the function call, in your code, no value is returned. That's why you get undefined.
The code executed without a return value, so the default return value by JavaScript is undefined

Is there a way to define a prototype property with a reference to another property?

Let's say a simple prototype is defined:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName
this.fullName = first + " " + last;
}
Now, I want to add a new property down the road called nickName. (but I don't want to use a method, that's already well documented)
Person.prototype.nickName = (what to put here to have firstName + first letter of lastName)
I used:
Person.prototype = {
get nickName(){
return this.firstName+ this.lastName.charAt(0);
}
};
But it doesn't work for already created Persons.
I just want to know if there is a way to do it, besides including it in the initial definition.
You can just add a new method to the prototype:
Person.prototype.nickname = function() {
return this.firstName + this.lastName.charAt(0);
}

JavaScript - Apply one method to many objects

I have heard about the prototype method to apply one function or variable to several objects. But it does not work for me somehow. I created many objects kind of like this:
var item = {
a: {
aa: "lalala",
ab: 1,
something: 3
},
b: {
ba: "jfjb",
bb: 2,
something: 4
}
}
But when I know use the prototype method
item.prototype.bob = 2;
it does not work and shows me the error
Cannot set property 'bob' of undefined"
Same for a method
item.prototype.bob = function() {
100 - this.something;
this.something++;
}
Do you know what I do wrong or is there a different method to apply the same variable or function to many objects?
You confuse classes with object instances. You just have an anonymous object. item is the instance, not the class.
In the snippet below, a class is declared (Item, with capital i), an instance is created (item), and the prototype of the class is modified. You will see then that you can set a property on the prototype and read it though the instance, if you like.
var Item = function() {
a = {
aa: "lalala",
ab: 1,
something: 3
};
b = {
ba: "jfjb",
bb: 2,
something: 4
};
}
var item = new Item();
Item.prototype.bob = 'x';
alert(item.bob);
The classic way is
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.greet = function() {
console.log(this.firstName + " says hello");
}
var pete = new Person("Peter", "Pan");
pete.greet();
Note that the prototype attribute is on the constructor (the function object we invoke with new to construct the object), not the constructed object itself.
In ECMAScript 6, you'll be able to write this in a more compact way:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
greet() {
console.log(this.firstName + " says hello");
}
}
new Person("Peter", "Pan").greet();
The prototype property is called on the class name and not on the object name. So, if item is an object of class MyClass then you should write:
MyClass.prototype.bob = 2;
You can find more information on the links below:
http://www.w3schools.com/js/tryit.asp?filename=tryjs_object_prototype5
http://www.w3schools.com/js/js_object_prototypes.aspenter link description here
Here your item is an object by itself,it does not has any constructor, so you cannot define or set on prototype.Your code throws error
To fix this, it has to be something like the below
function item(a,b){
this.a=a;
this.b=b;
}
function a(aa,ab,something){
this.aa=aa;
this.ab=ab;
this.something=something
}
item.prototype.bob=2;
item.prototype.method1 = function() {
100 - this.something;
this.something++;
}
Hope this helps

How to add methods to a (JSON) object's prototype?

Let's say I receive some JSON object from my server, e.g. some data for a Person object:
{firstName: "Bjarne", lastName: "Fisk"}
Now, I want some methods on top of those data, e.g. for calculating the fullName:
fullName: function() { return this.firstName + " " + this.lastName; }
So that I can
var personData = {firstName: "Bjarne", lastName: "Fisk"};
var person = PROFIT(personData);
person.fullName(); // => "Bjarne Fisk"
What I basically would want to do here, is to add a method to the object's prototype. The fullName() method is general, so should not be added to the data object itself. Like..:
personData.fullName = function() { return this.firstName + " " + this.lastName; }
... would cause a lot of redundancy; and arguably "pollute" the data object.
What is the current best-practice way of adding such methods to a simple data object?
EDIT:
Slightly off topic, but if the problem above can be solved, it would be possible to do some nice pseudo-pattern matching like this:
if ( p = Person(data) ) {
console.log(p.fullName());
} else if ( d = Dog(data) ) {
console.log("I'm a dog lol. Hear me bark: "+d.bark());
} else {
throw new Exception("Shitty object");
}
Person and Dog will add the methods if the data object has the right attributes. If not, return falsy (ie. data does not match/conform).
BONUS QUESTION: Does anyone know of a library that either uses or enables this (ie makes it easy)? Is it already a javascript pattern? If so, what is it called; and do you have a link that elaborates? Thanks :)
Assuming your Object comes from some JSON library that parses the server output to generate an Object, it will not in general have anything particular in its prototype ; and two objects generated for different server responses will not share a prototype chain (besides Object.prototype, of course ;) )
If you control all the places where a "Person" is created from JSON, you could do things the other way round : create an "empty" Person object (with a method like fullName in its prototype), and extend it with the object generated from the JSON (using $.extend, _.extend, or something similar).
var p = { first : "John", last : "Doe"};
function Person(data) {
_.extend(this, data);
}
Person.prototype.fullName = function() {
return this.first + " " + this.last;
}
console.debug(new Person(p).fullName());
There is another possibility here. JSON.parse accepts a second parameter, which is a function used to revive the objects encountered, from the leaf nodes out to the root node. So if you can recognize your types based on their intrinsic properties, you can construct them in a reviver function. Here's a very simple example of doing so:
var MultiReviver = function(types) {
// todo: error checking: types must be an array, and each element
// must have appropriate `test` and `deserialize` functions
return function(key, value) {
var type;
for (var i = 0; i < types.length; i++) {
type = types[i];
if (type.test(value)) {
return type.deserialize(value);
}
}
return value;
};
};
var Person = function(first, last) {
this.firstName = first;
this.lastName = last;
};
Person.prototype.fullName = function() {
return this.firstName + " " + this.lastName;
};
Person.prototype.toString = function() {return "Person: " + this.fullName();};
Person.test = function(value) {
return typeof value.firstName == "string" &&
typeof value.lastName == "string";
};
Person.deserialize = function(obj) {
return new Person(obj.firstName, obj.lastName);
};
var Dog = function(breed, name) {
this.breed = breed;
this.name = name;
}
Dog.prototype.species = "canine";
Dog.prototype.toString = function() {
return this.breed + " named " + this.name;
};
Dog.test = function(value) {return value.species === "canine";};
Dog.deserialize = function(obj) {return new Dog(obj.breed, obj.name);};
var reviver = new MultiReviver([Person, Dog]);
var text = '[{"firstName": "John", "lastName": "Doe"},' +
'{"firstName": "Jane", "lastName": "Doe"},' +
'{"firstName": "Junior", "lastName": "Doe"},' +
'{"species": "canine", "breed": "Poodle", "name": "Puzzle"},' +
'{"species": "canine", "breed": "Wolfhound", "name": "BJ"}]';
var family = JSON.parse(text, reviver)
family.join("\n");
// Person: John Doe
// Person: Jane Doe
// Person: Junior Doe
// Poodle named Puzzle
// Wolfhound named BJ
This depends on you being able to unambiguously recognizing your types. For instance, if there were some other type, even a subtype of Person, which also had firstName and lastName properties, this would not work. But it might cover some needs.
If you're dealing with plain JSON data then the prototype of each person object would simply be Object.prototype. In order to make it into an object with a prototype of Person.prototype you'd first of all need a Person constructor and prototype (assuming you're doing Javascript OOP in the traditional way):
function Person() {
this.firstName = null;
this.lastName = null;
}
Person.prototype.fullName = function() { return this.firstName + " " + this.lastName; }
Then you'd need a way to turn a plain object into a Person object, e.g. if you had a function called mixin which simply copied all properties from one object to another, you could do this:
//example JSON object
var jsonPerson = {firstName: "Bjarne", lastName: "Fisk"};
var person = new Person();
mixin(person, jsonPerson);
This is just one way of solving the problem but should hopefully give you some ideas.
Update: Now that Object.assign() is available in modern browsers, you could use that instead of writing your own mixin function. There's also a shim to make Object.assign() work on older browsers; see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill.
You should probably not do this.
JSON allows you to serialize a state, not a type. So in your use case, you should do something like this :
var Person = function ( data ) {
if ( data ) {
this.firstName = data.firstName;
this.lastName = data.lastName;
}
};
Person.prototype.fullName = function ( ) {
return this.firstName + ' ' + this.lastName;
};
//
var input = '{"firstName":"john", "lastName":"Doe"}';
var myData = JSON.parse( input );
var person = new Person( myData );
In other words you want to change prototype (a.k.a. class) of existing object.
Technically you can do it this way:
var Person = {
function fullName() { return this.firstName + " " + this.lastName; }
};
// that is your PROFIT function body:
personData.__proto__ = Person ;
After that if you will get true on personData instanceof Person
Use the new-ish Object.setPrototypeOf(). (It is supported by IE11 and all the other browsers now.)
You could create a class/prototype that included the methods you want, such as your fullName(), and then
Object.setPrototypeOf( personData, Person.prototype );
As the warning (on MDN page linked above) suggests, this function is not to be used lightly, but that makes sense when you are changing the prototype of an existing object, and that is what you seem to be after.
I don't think it is common to transport methods with data, but it seems like a great idea.
This project allows you to encode the functions along with your data, but it is not considered standard, and requires decoding with the same library of course.
https://github.com/josipk/json-plus
Anonymous objects don't have a prototype. Why not just have this:
function fullName(obj) {
return obj.firstName + ' ' + obj.lastName;
}
fullName(person);
If you absolutely must use a method call instead of a function call, you can always do something similar, but with an object.
var Person = function (person) { this.person = person; }
Person.prototype.fullName = function () {
return this.person.firstName + ' ' + this.person.lastName;
}
var person = new Person(personData);
person.fullName();
You don't need to use prototypes in order to bind a custom method in your barebone object.
Here you have an elegant example that don't pollute your code avoiding redundant code
var myobj = {
title: 'example',
assets:
{
resources: ['zero', 'one', 'two']
}
}
var myfunc = function(index)
{
console.log(this.resources[index]);
}
myobj.assets.giveme = myfunc
myobj.assets.giveme(1);
Example available in https://jsfiddle.net/bmde6L0r/

Categories