why can't I change object property in JavaScript - javascript

I made a mistake with the age property on these objects and when I try to reassign different values later, it won't change it at all.
I want this to work with the Object.create Method. What should I do to fix this?
var personProto = {
calculateAge: function() {
console.log(2019 - this.yearOfBirth)
},
fullName: function() {
console.log(this.name + ' ' + this.lastName)
}
}
var sam = Object.create(personProto, {
name: { value: "samuel" },
yearOfBirth: { value: 1092 },
lastName: { value: "max" },
job: { value: "developer" }
});
sam.yearOfBirth = 1992;
sam.calculateAge(); // 927
console.log(sam.calculateAge()); is giving me 927 assuming yearsOfBirth is still 1092 even if I changed it to 1992 and the output was supposed to be 27.

By default, properties assigned using Object.create are not writable. Attempting to write to a non-writable property is a silent error in JavaScript - one of many reasons to use Strict Mode.
Here is your code again, but in Strict Mode:
'use strict';
var personProto = {
calculateAge:function(){
console.log(2019 -this.yearOfBirth)
},
fullName:function(){
console.log(this.name + ' ' + this.lastName)
}
}
var sam = Object.create(personProto, {
name:{value:'samuel'},
yearOfBirth:{value:1092},
lastName:{value:'max'},
job:{value:'developer'}
});
sam.yearOfBirth = 1992;
console.log(sam.calculateAge());
927
Notice that it now fires an error and tells you exactly what's wrong.
To fix this, just make the properties writable.
'use strict';
var personProto = {
calculateAge:function(){
console.log(2019 -this.yearOfBirth)
},
fullName:function(){
console.log(this.name + ' ' + this.lastName)
}
}
var sam = Object.create(personProto, {
name:{value:'samuel',writable:true},
yearOfBirth:{value:1092,writable:true},
lastName:{value:'max',writable:true},
job:{value:'developer',writable:true}
});
sam.yearOfBirth = 1992;
console.log(sam.calculateAge());
927

The second argument to Object.create uses property descriptors, and the writable attribute defaults to false when you don't specify it.
I would recommend to drop the second argument entirely, and instead use Object.assign to create the properties on the new object:
var sam = Object.assign(Object.create(personProto), {
name: 'samuel',
yearOfBirth: 1092,
lastName: 'max',
job: 'developer',
});

Related

How Can I Change Constant Array in Javascript?

I have an array data but it declared with const. I am rather confused to change the data in array. Here is my array:
const person = {
name: "Person A", ---> the data I want to change
age: 100,
favDrinks: [
"coffee",
"temulawak", --->> the data I want to change
"tea"
],
greeting: function() {
console.log("Hello World"); --->> the data I want to change
}
}
How can I change the data of person.name, person.favDrinks[1], and greeting function of "Hello World". Is there a possible way to change constant data? I want to change to text strings. Here is my code :
function personName(nama ){
let person.name = nama;
person.push("name:" nama );
}
console.log(personName("Molly"));
But they are all wrong. Please help me. Thank you. :)
You are doing a couple of things wrong.
You are pushing into an object, instead of an array.
You are redefining the object person by using let inside your function.
You can change properties of a const object; however, you cannot reassign it.
Simply add return person
const person = {
name: "Person A",
age: 100,
favDrinks: ["coffee", "temulawak", "tea"],
greeting: function () {
console.log("Hello World");
},
};
function personName(nama) {
person.name = nama;
return person;
}
console.log(personName("Molly"));
This is what you'll get after your changes have been made:
{
name: 'Molly',
age: 100,
favDrinks: [ 'coffee', 'temulawak', 'tea' ],
greeting: [Function: greeting]
}
You are using let to create a variable with the name person.name which is not possible and then pushing it into person, in your case this is not what you should do, instead just change the values directly.
function personName(nama) {
person.name = name
return person
}
console.log(personName("Molly"));
if a constant variable is a string or a jumber, it cannot be changed. but if it is an array or object it cannot be changed but items in the object or array can be added, removed, or edited.
person is an object, not an array.
You can change properties values of a constant object.
Working Demo :
const person = {
name: "Person A",
age: 100,
favDrinks: [
"coffee",
"temulawak",
"tea"
],
greeting: function() {
console.log("Hello World");
}
};
person.name = "Person B";
person.favDrinks[1] = "Soft Drinks";
person.greeting = function() {
console.log('Hello Guys!');
}
console.log('updated object', person);
I am following " Learn javascript " on Scrimba and I got into a weird situation.
I learned that const variables can not be reassigned and there are methods in arrays and objects where you can add or remove elements from them (e.g arr.push())
const s = [5, 7, 2];
function editInPlace() {
"use strict";
s = [2, 5, 7];
}
editInPlace();
Console error:
Error: SyntaxError: unknown: "s" is read-only (/index.js:1)
But here comes the magic, when they assigned the const array variables new values with specific indexes then it worked well.
const s = [5, 7, 2];
function editInPlace() {
"use strict";
//s = [2, 5, 7];
s[0] = 2;
s[1] = 5;
s[2] = 7;
}
editInPlace();
console.log(s)
Console output:
[2, 5, 7]
Now I am not able to understand why is this happening.
Looking forward to listen from you.

setting "x" number of parameter to function property

I am trying to create a generic function where you are able to pass an object that has a property of a random function. With this you should be able to set a property stating the key and value for each parameter of the function.
the generic function should then call this "random" function with all the parameters.
However im not quite sure how to do it?
// Keep in mind its created for demonstration purposes
var functionOne = function(id)
{
return id;
}
var functionTwo = function(id,name)
{
return id + ' 'name;
}
var functionThree = funciton(id,name,age)
{
return id + ' '+name+' '+age;
}
var obj = [
{
callback: functionOne,
callbackParameters: [{key: 'id', value: 1}]
},
{
callback: functionTwo,
callbackParameters: [{key: 'id', value: 1}, {key: 'name', value:'Marc'}]
},
{
callback: functionThree,
callbackParameters: [{key: 'id', value: 1}, {key: 'name', value: 'Marc'}, {key: 'age', value: 45}]
}
]
obj.forEach(function(x){
//How do i call it with the correct keys? :(
})
Fiddle
You can call apply() on a function in JS and pass an array of parameters into it. So you could use the following assuming your callbackParameters are always in the correct order.
obj.forEach(function(x){
var parameters = x.callbackParameters.map(function(p) { return p.value; });
console.log(x.callback.apply(this, parameters));
})
Updated fiddle https://jsfiddle.net/y6oh1078/1/
Edit: Further reading
If you are interested in more ways to manipulate functions in JS, the following article on currying is a good read - https://www.sitepoint.com/currying-in-functional-javascript/
You cannot do this. This would require something like reflection, i.e. forEach anonymous function should know the definition of every callback function and get names (and what is much more important - order) of its arguments.
However, you can do the following:
var functionOne = function (o) {
return o.id;
};
var functionTwo = function (o) {
return o.id + ' ' + o.name;
};
var functionThree = function (o) {
return o.id + ' ' + o.name + ' ' + o.age;
};
var obj = [{
callback : functionOne,
callbackParameters : [{
key : 'id',
value : 1
}
]
}, {
callback : functionTwo,
callbackParameters : [{
key : 'id',
value : 1
}, {
key : 'name',
value : 'Marc'
}
]
}, {
callback : functionThree,
callbackParameters : [{
key : 'id',
value : 1
}, {
key : 'name',
value : 'Marc'
}, {
key : 'age',
value : 45
}
]
}
];
// Now, are you able to generate `o` objects dynamically using something like:
obj.forEach(function (x) {
var o = {};
x.callbackParameters.forEach(function (p) {
o[p.key] = p.value;
});
console.log(x.callback(o));
});
P.S. Actually, you can dynamically get the names and order of function arguments, but you do not want to do this.
If you are still interested in this, read this question.

Using object variable within function. JavaScript

I have recently started to learn JavaScript and would like to know if it is possible to use a object variable in a function directly within the same object. Here is my code so far.
var user = {
name: 'Example',
age: 687,
address: {
firstLine: '20',
secondLine: 'St Fake',
thirdLine: 'Fakeland'
},
logName: function(inputName, inputAge){
console.log(user.name);
console.log(user.age);
console.log(inputAge);
console.log(inputName);
}
};
user.logName('Richard', 20);
How is it possible to link to the name and age variables of user in the function without needing to prefix the object name onto the variable?
In most cases, you can just use the this keyword to get the object on which your function was called as a method upon. In your example:
var user = {
name: 'Example',
age: 687,
address: {
firstLine: '20',
secondLine: 'St Fake',
thirdLine: 'Fakeland'
},
logName: function(inputName, inputAge) {
console.log(this.name);
// ^^^^
console.log(this.age);
// ^^^^
console.log(inputAge);
console.log(inputName);
}
};
user.logName('Richard', 20); // method call on `user`,
// so `this` will become the `user` in the function
Welcome to the "this" key word!
Just reference it by this.value
You can use the this keyword . You can better understand this keyword using this article
The code will be like this
var user = {
name: 'Example',
age: 687,
address: {
firstLine: '20',
secondLine: 'St Fake',
thirdLine: 'Fakeland'
},
logName: function (inputName, inputAge) {
console.log(this.name);
console.log(this.age);
console.log(inputAge);
console.log(inputName);
}
};
user.logName('Richard', 20);

The property() method of function class right using

Example in the documentation:
App.Person = Ember.Object.extend({
// these will be supplied by `create`
firstName: null,
lastName: null,
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
var ironMan = App.Person.create({
firstName: "Tony",
lastName: "Stark"
});
ironMan.get('fullName') // "Tony Stark"
I can't understand why I must specify dependencies like .property('firstName', 'lastName') if I had indicated what needs to return: return this.get('firstName') + ' ' + this.get('lastName') and the example above can work without it (just using property()).
Thanks.
It's for caching.
From docs:
By default the function backing the computed property will only be
called once and the result will be cached. You can specify various
properties that your computed property is dependent on. This will
force the cached result to be recomputed if the dependencies are
modified.

How to inherit and chain String without polluting String.prototype?

What I want to be able to do is something like this:
var where = new Where();
where('a'); // returns a string 'WHERE a' that I can chain against
where('a').andWhere('b'); // reuturns 'WHERE a AND b' that is also chainable
where('a').andWhere('b').orWhere('c'); // 'WHERE a AND b OR c', and so on ...
The where methods should return what is for all intents and purposes a string, with all string like methods, but with the two custom andWhere and orWhere methods.
When I tried inheriting from Sting.prototype, my where methods returned an object, not a string. Of course, if I returned a string directly from the methods, they didn't have the andWhere and orWhere methods, so chaining broke.
The code below does what I want, but it does it by polluting the String.prototype. Is there a way to get the same behavior, but encapsulated in a custom object?
Object.defineProperty(String.prototype, "andWhere", {
value: function _andWhere(clause) {
return [this, 'AND', clause].join(' ');
},
configurable: true,
enumerable: false,
writeable: true
});
Object.defineProperty(String.prototype, "orWhere", {
value: function _orWhere(clause) {
return [this, 'OR', clause].join(' ');
},
configurable: true,
enumerable: false,
writeable: true
});
function where(clause){
return ['WHERE', clause].join(' ');
}
where('a').andWhere('b').orWhere('c');
// => 'WHERE a AND b OR c'
Edit
I still want to have access to all the string methods off the object directly. In other words the returned object acts just like a string, but with a couple more methods. For example:
var whereStr = where('a').andWhere('b').orWhere('c');
whereStr.length; // => 18
whereStr.concat(' and so on'); // => 'WHERE a AND b OR c and so on'
If it makes any difference, this is primarily for Node, but ideally would work for any recent (ES5) javascript implementation. Again, this works perfectly if I'm bad and use String.prototype, I'm hoping there's a way to do a drop in replacement.
UPDATED Added in an example of creating the length property as a "getter".
function Where(conditional) {
var thisObj = this;
//Setup the length property's "getter"
this.__defineGetter__( "length", function() {
return thisObj.clause.length;
});
this.start( conditional );
}
Where.prototype = {
AND_STR: " AND ",
OR_STR: " OR ",
add: function(conditional, prefix) {
this.clause += prefix + conditional;
},
and: function(conditional) {
this.add( conditional, this.AND_STR );
return this;
},
or: function(conditional) {
this.add( conditional, this.OR_STR );
return this;
},
start: function(conditional) {
this.clause = "WHERE " + conditional;
},
toString: function() {
return this.clause;
}
}
//Use it like this (this shows the length of the where statement):
alert( new Where( "a" ).and( "b" ).or( "c" ).length );

Categories