Javascript prototype - object.create issue - javascript

Im trying to learn about object.create and prototypal inheritance and have the following:
var Employee = {
'attributes': {},
getAttributes: function() {
return this.attributes;
},
addAttribute: function(attribute) {
if (! this.attributes.hasOwnProperty(attribute)) {
this.attributes.extend(attribute);
}
}
};
var OfficeEmployee = Object.create(Employee);
var OfficeEmployeeInstance = Object.create(OfficeEmployee, {'attributes': {'id': 123, 'name': 'Bob'}});
console.log(OfficeEmployeeInstance.attributes);
OfficeEmployeeInstance.addAttribute({'salary': '100'});
console.log(OfficeEmployeeInstance.getAttributes());
It doesnt work as i expect it should though and throws errors:
console.log(OfficeEmployeeInstance.attributes);
is undefined
and
console.log(OfficeEmployeeInstance.getAttributes());
gives error:
Uncaught TypeError: Cannot call method 'hasOwnProperty' of undefined tester.js:39
Employee.addAttribute tester.js:39
(anonymous function)
What am i doing wrong here?

The second argument of Object.create has to be a properties object. That's an object with a defined structure and specific properties:
var OfficeEmployeeInstance = Object.create(OfficeEmployee, {
'attributes': {
value: {'id': 123, 'name': 'Bob'},
writeable: true,
enumerable: true
}
});
You can find the supported properties here.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
When using .create you should pass it an argument of someObject.prototype, rather than a constructor name. The documentation above should help.

Related

Why can I not assign my items to my object's constant?

I made an object in my chrome extension and added a constant to it
const myObj = {};
Object.defineProperty(myObj , "DATABASES", { value: {}, writable: true, configurable: true });
Then I tried to add a value to that constant
myObj.DATABASES["key1"] = new Set(
{ a: "aaaa", b: "bbbb" }
);
The last line results in the following error, which doesn't make it clear to me which part of the statement is a problem:
Uncaught TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
Can somebody tell me what's wrong with that last part?
Set expects an iterable object, like array, and you're passing it an object: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Syntax
I corrected the syntax with Clarity's link. It should be done as follows:
myObj.DATABASES["key1"] = new Set();
myObj.DATABASES["key1"].add({ a: "aaa", b: "bbbb" });

javascript Object.create: setting properties "directly" vs setting properties declared in propertiesObject

I apologize in advance if this has been asked elsewhere or if I have missed something important in the docs, well, but I need to ask this:
Let's say an object is being created without defining the respective properties
cons objA = Object.create({
init(text) {
this.text = text;
}
});
or an object is being created and the respective property has been declared in the properties object
const objB = Object.create({
init(text) {
this.text = text;
}
}, {
text: {
value: '',
writable: true
}
});
I understand that defining properties in the propertiesObject of Object.create helps defining and providing better contracts,
but
do these two scenarios vary in respect to the text property?
Yes, they vary - there is difference between a and b results
const a = Object.create({
init(text) {
this.text = text;
}
});
const b = Object.create({
init(text) {
this.text = text;
}
}, {
text: {
value: '',
writable: true
}
});
console.log(Object.getOwnPropertyNames(a))
console.log(Object.getOwnPropertyNames(b))
a.init('a text');
b.init('b text');
console.log(Object.getOwnPropertyDescriptor(a, 'text'))
console.log(Object.getOwnPropertyDescriptor(b, 'text'))
a returns:
{
"value": "a text",
"writable": true,
"enumerable": true,
"configurable": true
}
b returns:
{
"value": "b text",
"writable": true,
"enumerable": false,
"configurable": false
}
By default property is enumerable and configurable unless you define property by Object.defineProperty or Object.create. You can define them as you did with writable.
Enumerable works in certain object-property enumerations, such as the for..in.
Configurable means that you cannot use Object.defineProperty again on this property (there will be Cannot redefine property: text error).
Other than that - before you use init() - a object will have undefined text property (that is not enumerable, not configurable, writable) and object b will not have any property.

Complex objects in javascript

I'm fiddling around with a library called bcoin for node. Running the following code:
chain.on('block', function(block) {
console.log('Connected block to blockchain:');
block.txs.forEach(function(t) {
t.inputs.forEach(function(i) {
console.log(typeof i, i);
console.log(JSON.stringify(i));
});
});
});
This is the response I'm getting:
Connected block to blockchain:
object { type: 'coinbase',
subtype: null,
address: null,
script: <Script: 486604799 676>,
witness: <Witness: >,
redeem: null,
sequence: 4294967295,
prevout: <Outpoint: 0000000000000000000000000000000000000000000000000000000000000000/4294967295>,
coin: null }
{"prevout":{"hash":"0000000000000000000000000000000000000000000000000000000000000000","index":4294967295},"script":"04ffff001d02a402","witness":"00","sequence":4294967295,"address":null}
Notice that even though the attribute type for example, is shown when we print i, that attribute does not exist when we JSON.stringify the object. If I tried to console.log(i.type) I'd get undefined.
How is that possible? And what is a good way of debugging what's going on with an object?
JSON.stringify will only includes enumerable properties that are not functions.
So if you define a property and set as non-enumerable, it will not be a part of JSON string.
var obj = {
a: 'test'
};
// Non-enumerable property
Object.defineProperty(obj, 'type', {
enumerable: false,
value: 'Test'
});
// Get property
Object.defineProperty(obj, 'type2', {
get: function(){
return 'Test 2'
}
});
console.log(JSON.stringify(obj), obj);
console.log(obj.type, obj.type2)

javascript: add nested attribute in object

Wit this example object:
obj = {
id: '123',
attr: 'something'
}
Now I want to add the attribute link in the attribute data. Sometimes data is already existing, but in this example data doesn't exist.
So if I do
obj.data.link = 'www.website.com';
I get the error TypeError: Cannot set property 'link' of undefined.
Result should be:
obj = {
id: '123',
attr: 'something',
data: {
link: 'www.website.com'
}
}
You need to create the data object first:
obj.data = {};
obj.data.link = 'www.website.com';
or you can do it all at once:
obj.data = {
link: 'www.website.com'
};
if data may or may not already by there, there's a handy shortcut that will use the existing one if it's there or create a new one if not:
obj.data = obj.data || {};
obj.data.link = 'www.website.com';
That uses the JavaScript's curiously-powerful || operator.
You need to initialize the data property. You can do something like this:
var obj = {
id: '123',
attr: 'something'
};
obj.data = {};
obj.data.link = 'www.website.com';
In the case for the property existing you can check before assigning link.
if (!obj.data) {
obj.data = {};
}
And as stated in another answer you can use the or operator which I've heard is 'curiously powerful' =]
obj.data = obj.data || {};
That basically means if this value ( obj.data ) exists use it and if it doesn't use the right operand ( {} ). This works because of short circuit evaluation.
Javascript From 1.8.5 you can use the following method:
Object.defineProperty(obj, "data", {
value: {'link' : 'www.website.com'},
writable: true,
enumerable: true,
configurable: true
});
Good luck :)

Object.getOwnPropertyNames vs Object.keys

What's the difference between Object.getOwnPropertyNames and Object.keys in javascript? Also some examples would be appreciated.
There is a little difference. Object.getOwnPropertyNames(a) returns all own properties of the object a. Object.keys(a) returns all enumerable own properties. It means that if you define your object properties without making some of them enumerable: false these two methods will give you the same result.
It's easy to test:
var a = {};
Object.defineProperties(a, {
one: {enumerable: true, value: 1},
two: {enumerable: false, value: 2},
});
Object.keys(a); // ["one"]
Object.getOwnPropertyNames(a); // ["one", "two"]
If you define a property without providing property attributes descriptor (meaning you don't use Object.defineProperties), for example:
a.test = 21;
then such property becomes an enumerable automatically and both methods produce the same array.
Another difference is in case of array Object.getOwnPropertyNames method will return an extra property that is length.
var x = ["a", "b", "c", "d"];
Object.keys(x); //[ '0', '1', '2', '3' ]
Object.getOwnPropertyNames(x); //[ '0', '1', '2', '3', 'length' ]
Literal notation vs constructor when creating object. Here is something that got me.
const cat1 = {
eat() {},
sleep() {},
talk() {}
};
// here the methods will be part of the Cat Prototype
class Cat {
eat() {}
sleep() {}
talk() {}
}
const cat2 = new Cat()
Object.keys(cat1) // ["eat", "sleep", "talk"]
Object.keys(Object.getPrototypeOf(cat2)) // []
Object.getOwnPropertyNames(cat1) // ["eat", "sleep", "talk"]
Object.getOwnPropertyNames(Object.getPrototypeOf(cat2)) // ["eat", "sleep", "talk"]
cat1 // {eat: function, sleep: function, talk: function}
cat2 // Cat {}
// a partial of a function that is used to do some magic redeclaration of props
function foo(Obj) {
var propNames = Object.keys(Obj);
// I was missing this if
// if (propNames.length === 0) {
// propNames = Object.getOwnPropertyNames(Obj);
// }
for (var prop in propNames) {
var propName = propNames[prop];
APIObject[propName] = "reasign/redefine or sth";
}
}
So in my case the foo function didn't work if I gave it objects of the cat2 type.
There are other ways to create objects so there could be other kinks in there as well.
As was already explained, .keys doesn't return non-enumerable properties.
Regarding to examples, one of pitfall cases is an Error object: some of its properties are non-enumerable.
So while console.log(Object.keys(new Error('some msg'))) yields [],
console.log(Object.getOwnPropertyNames(new Error('some msg'))) yields ["stack", "message"]
console.log(Object.keys(new Error('some msg')));
console.log(Object.getOwnPropertyNames(new Error('some msg')));
Another difference is that (at least with nodejs) "getOwnPropertyNames" function does not guarantee keys order, that's why I usually use "keys" function :
Object.keys(o).forEach(function(k) {
if (!o.propertyIsEnumerable(k)) return;
// do something...
});

Categories

Resources