Make all properties of object mutable - javascript

How do i define properties of an object, so if one of them is changed all other are automatically updated.
I have come up with this code so far, but it doesn't work:
function CreateNamed(first, last) {
Object.defineProperties(this, {
"firstName": {
value: first,
writable: true
},
"lastName": {
value: last,
writable: true
},
"fullName": {
value: first + ' ' + last,
writable: true
}
});
}
So after a new object is created it can be changed appropriately:
var b = new CreateNamed('Bill', 'Gates'); // Bill Gates
b.firstName = 'Paul'; // b.fullName = Paul Gates
b.lastName = 'Wood'; // b.fullname = Paul Wood
b.fullName = 'Chuck Norris' // b.firstName = Chuck, b.lastName = Norris

value is not computed dynamically. It won't change as the object changes. In order to dynamically compute properties, you need to define getters and setters using get and set:
get
A function which serves as a getter for the property, or undefined if there is no getter. The function return will be used as
the value of property. Defaults to undefined.
set
A function which serves as a setter for the property, or undefined if there is no setter. The function will receive as only
argument the new value being assigned to the property. Defaults to
undefined.
function CreateNamed(first, last) {
this.first = first;
this.last = last;
Object.defineProperties(this, {
"firstName": {
get: function() { return this.first; },
set: function(name) { this.first = name; }
},
"lastName": {
get: function() { return this.last; },
set: function(name) { this.last = name; }
},
"fullName": {
get: function () { return this.first + ' ' + this.last },
set: function (name) {
if (!name.match(/^[a-z]+ [a-z]+$/))
throw new Error('I cannot parse that name')
var parts = name.split(' ')
this.first = parts[0];
this.last = parts[1];
}
}
});
}
var user = new CreateNamed('bob', 'smith');
document.write(user.fullName); // bob smith
user.firstName = "john";
document.write(user.fullName); // john smith
user.fullName = "tony brian";
document.write(user.firstName); // tony
document.write(user.lastName); // brian

#meagar's answer is correct.
But there is a simpler approach: just assign the firstName and lastName properties as usual, and then only define a getter and setter for fullName:
function CreateNamed(first, last) {
this.firstName = first;
this.lastName = last;
Object.defineProperty(this, "fullName", {
get: function () { return this.firstName + ' ' + this.lastName },
set: function (name) {
name = name.split(' ');
if(name.length != 2) throw new Error('I cannot parse that name');
this.firstName = name[0];
this.lastName = name[1];
}
});
}
function CreateNamed(first, last) {
this.firstName = first;
this.lastName = last;
Object.defineProperty(this, "fullName", {
get: function () { return this.firstName + ' ' + this.lastName },
set: function (name) {
name = name.split(' ');
if(name.length != 2) throw new Error('I cannot parse that name');
this.firstName = name[0];
this.lastName = name[1];
}
});
}
var ouput = [];
var user = new CreateNamed('bob', 'smith');
ouput.push(user.fullName); // bob smith
user.firstName = "john";
ouput.push(user.fullName); // john smith
user.fullName = "tony brian";
ouput.push(user.firstName); // tony
ouput.push(user.lastName); // brian
document.body.innerHTML = ouput.join('<br />');

Related

Why doesn't the setter method have any effect on other variables in my JavaScript object?

Can someone please explain why the "fullName" variable in my object does not change after the "setFirstName" setter method has changed the "firstName" variable to "NewFirstName". I am aware of the correct answer to this problem but I'm confused as to why the following solution does not also work.
This is a picture showing the below snippet being run
Here is the code:
<!DOCTYPE html>
<html>
<script>
var Person = function(firstAndLast) {
let firstName = firstAndLast.split(" ")[0];
let lastName = firstAndLast.split(" ")[1];
let fullName = firstName + " " + lastName;
// Getters
this.getFirstName = function() {
return firstName;
};
this.getLastName = function() {
return lastName;
};
this.getFullName = function() {
return fullName;
};
// Setters
this.setFirstName = function(first) {
firstName = first;
};
this.setLastName = function(last) {
lastName = last;
};
this.setFullName = function(name) {
fullName = name;
};
};
debugger;
var bob = new Person('Bob Ross');
console.log(bob.getFullName());
bob.setFirstName("NewFirstName");
console.log(bob.getFirstName());
console.log(bob.getFullName());
</script>
</html>
Because you're only calculating fullName once, it won't update dynamically.
You don't really want a variable for fullName, just a getter:
this.getFullName = function() {
return firstName + " " + lastName;
}
Remove
let fullName = firstName + " " + lastName;
Alternatively you can keep your variable and manually update it in both the setFirstName and setLastName functions, but really this is the kind of thing getters exist to do.

JS using a closure replicate an private set object only available through get/accessor method

I'm trying to create a function that uses a closure to replicate an object.
accessing the getter property within a private function.
function Container(param) {
var person = {
firstName: 'Jimmy',
lastName: 'Smith',
get fullName() {
return this.firstName + ' ' + this.lastName;
},
set fullName (name) {
var words = name.toString().split(' ');
this.firstName = words[0] || '';
this.lastName = words[1] || '';
}
}
}
// Attempting to clone private getter don't know how to access it.
function objectClone(person) {
var orginal = person //Trying to access the private method
var clone = function cloneObj { Object.assign({}, original); }
clone.prototype.spillSecret = function() { alert(this.getfullName()); }
;}
It seems like you're trying to create a new instance of a Container. Firstly, we should fix up that code:
function Container(param) {
this.firstName = 'Jimmy';
this.lastName = 'Smith';
Object.defineProperty(this, 'fullName', {
get: function() {
return this.firstName + ' ' + this.lastName;
},
set: function(name) {
var words = name.toString().split(' ');
this.firstName = words[0] || '';
this.lastName = words[1] || '';
}
});
}
Now, to create a new Container object, we use new:
var person = new Container();
person will have the get and set methods for fullName on it.

Creating a Class Method

function Person(firstName = "John", lastName = 'Doe', age = 0, gender = 'Male') {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.gender = gender;
this.sayFullName = function() {
return this.firstName + " " + this.lastName
};
}
Person.prototype.greetExtraTerrestrials = function(raceName) {
return `Welcome to Planet Earth ${raceName}`;
};
What is wrong with this code? Doesn't it create a class method called greetExtraTerrestrials?
Don't place that function on prototype, place that on Class itself like
Person.greetExtraTerrestrials = function(raceName) {
return `Welcome to Planet Earth ${raceName}`;
};
and call it like
Person.greetExtraTerrestrials('ABC');
You can do both! The difference in
class Person(...) {
...
}
Person.myFunction = function(val) { // This is a public function
return val;
}
Person.prototype.myFunction = function(val) { // This is a private function
return val;
}
is how you access it.
Access the public function :
var r = Person.myFunction("Hello!");
console.log(r);
Access the private function:
var person1 = new Person(...);
var r = person1.myFunction("Hello!");
console.log(r);
See also this question.
Actually it works, but firstly you need to create an instance of Person to be able call its methods. For example:
var john = new Person("John");
console.log(john.greetExtraTerrestrials("predator"));

Javascript - Scope and This

I have some code below. the problem I don't understand is why I don't have to refer to 'children' object via this.children but then accessing the firstname or surname, i have to use this.firstname....
Please help me understand why.
function User(first, sur) {
var firstName;
var surName;
var age;
var children = [];
this.firstName = first;
this.surName = sur;
this.getDisplayName = function() {
return this.firstName + ' ' + this.surName;
};
this.getTotalLength = function() {
return (this.firstName.length + this.surName.length);
};
this.displayFullName = function() {
return (this.firstName + ' ' + this.surName);
};
this.changeMaidenname = function(newSurname) {
if (newSurname)
{
this.surName = newSurname;
}
};
this.addChild = function(childUser) {
children.push(childUser);
};
this.numberOfChildren = function() {
return children.length;
};
this.killChild = function(childUser) {
children.forEach(function(item,index)
{
if (item.firstName === childUser.firstName && item.surName === childUser.surName)
{
children.splice(index, 1);
}
}
)
};
};
module.exports.User = User
In js,this keyword is used to create public variables whereas the var limits the scope of that variable to that particular function. :).You cant even access children object unless it is defined this.children=[]

JavaScript Inheritance constructor.prototype

I can't understand line 4.
If I write like derive.constructor.prototype,
The error will occur.
And also, What is base.apply(derive, baseArgs);?
I thought that I can do like base(baseArg) I couldn't do that.
function initializeBase(derive, base, baseArgs) {
base.apply(derive, baseArgs);
for(var prop in base.prototype) {
var proto = derive.constructor.prototype;
if(!proto[prop]) {
proto[prop] = base.prototype[prop];
}
}
}
var Member = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
};
Member.prototype.getName = function() {
return this.firstName + ' ' + this.lastName;
};
var SpecialMember = function(firstName, lastName, role) {
initializeBase(this, Member, [firstName, lastName]);
this.role = role;
};
SpecialMember.prototype.isAdministrator = function() {
return (this.role == 'Administrator');
};
var mem = new SpecialMember('Kotaro', 'Hayafune', 'Administrator');
document.writeln('Name: ' + mem.getName() + '<br>');
document.writeln('Administrator: ' + mem.isAdministrator());
Not sure what your variables contain here but usually if you want the prototype you would write:
var proto = derive.prototype;
and if you wanted the constructor you'd write:
var constr = derive.prototype.constructor;

Categories

Resources