I need to know if is possible to make instances of a javascript class that has non-enumerable attributes, for example
// Constructor
function MyClass(a) {
Object.defineProperty(this, '_number', {
enumerable: false
});
this.number = a; // Call setter for '_number'
}
// Getters and setters for '_number'
Object.defineProperty(MyClass.prototype, 'number', {
get: function() {
return this._number;
},
set: function(n) {
// Validate 'n' here
this._number = n;
}
});
What I wanted this code to do is to define the property _number on any instance of MyClass, making it not enumerable so that instance private variables such as _number wouldn't be listed in, suppose, a for in structure. You would use the number getter/setter to alter the private variable _number.
I have tried declaring the _number and number properties both inside the constructor and on MyClass.prototype with no success...
Any help would be appreciated!
Your approach is fine, you just need to watch out for the other attribute values which default to false:
function MyClass(a) {
Object.defineProperty(this, '_number', {
value: 0, // better than `undefined`
writable: true, // important!
enumerable: false, // could be omitted
configurable: true // nice to have
});
this.number = a; // Call setter for '_number'
}
// Getters and setters for '_number'
Object.defineProperty(MyClass.prototype, 'number', {
get: function() {
return this._number;
},
set: function(n) {
// Validate 'n' here
this._number = n;
},
enumerable: true, // to get `.number` enumerated in the loop
configurable: true // nice to have
});
Related
Somehow I can read the property of a getter, but I can't delete it.
(I can delete getters/setters defined w/o using Object.defineProperties)
var hello = {
get num() {
return 123;
}
}
delete hello.num;
// returns true
However,
var hello = {};
Object.defineProperties(hello, {
num: {
get() {
return 123;
}
}
}
delete hello.num;
// returns false
The problem is that using the .defineProperties their is a property called writable
By default, it is set to False set it to true there is also a property called configurable
set it to true as well You can see the following code example to achieve this
'use strict'
Object.defineProperty(window, 'hello',{
get: ()=>"hello to you!",
configurable: true //make this true
and for the writeable property you can set it like this:
Object.defineProperty(obj, 'key', {
enumerable: false,
configurable: True,
writable: True,
value: 'static'
});
Trying to define a hashCode method on Object.prototype as well as String.prototype and Number.prototype. I'm defining the prototype methods using:
Object.defineProperty(Object.prototype, 'hashCode', {
value:function() {/*code*/},
enumerable:false
});
String.prototype.hashCode = function() {/*code*/};
Number.prototype.hashCode = function() {/*code*/};
When I create a number or string with any of ('', new String(), 3, new Number()), and call hashCode on the instance, the Object.prototype.hashCode method always runs instead of String.prototype.hashCode or Number.prototype.hashCode.
What's wrong?
Make the property descriptor writable: true or it will be inherited as non-writable when writing that property on objects that inherit it.
http://jsfiddle.net/5ox1a0f2 – squint
Object.defineProperty(Object.prototype, 'hashCode', {
value:function() {console.log('object')},
enumerable:false,
writable:true
});
String.prototype.hashCode = function() {console.log('string')};
Number.prototype.hashCode = function() {console.log('number')};
4..hashCode()
Mixing property definitions and property assignments can lead to this kind of problems.
It works if you also use property definition in String.prototype and Number.prototype:
Object.defineProperty(Object.prototype, 'hashCode', {
value: function() {console.log('object')},
enumerable: false
});
Object.defineProperty(String.prototype, 'hashCode', {
value: function() {console.log('string')},
enumerable: false
});
Object.defineProperty(Number.prototype, 'hashCode', {
value: function() {console.log('number')},
enumerable: false
});
(4).hashCode(); // "number"
('').hashCode(); // "string"
However, if you are only using property definitions because you don't want enumerability, but don't care about configurability nor writability, it may be more convenient to define the methods via assignment, and then redefine the enumerability:
Object.prototype.hashCode = function() {console.log('object')};
String.prototype.hashCode = function() {console.log('string')};
Number.prototype.hashCode = function() {console.log('number')};
Object.defineProperty(Object.prototype, 'hashCode', {enumerable: false});
Object.defineProperty(String.prototype, 'hashCode', {enumerable: false});
Object.defineProperty(Number.prototype, 'hashCode', {enumerable: false});
(4).hashCode(); // "number"
('').hashCode(); // "string"
When calling the add function of my GroceryList class, I get an error:
TypeError: this.list.push is not a function
Why is this?
class GroceryList {
constructor() {
this.list = {
value: [],
writable: false,
enumerable: true
};
}
add(item) {
this.list.push(item);
}
getAll() {
return this.list;
}
getItemIndex(value) {
var index = this.list.length;
while(--index > -1) {
if(this.list[index] === value) {
return index;
}
}
return -1;
}
}
You are confusing
A whole object
vs
A list as an attribute of that object
The list object contains a list, but that does not mean it is a list. You should write list.value.push(x)
It seems you are trying to use a property descriptor. However, those descriptors only work with Object.defineProperty.
this.list = {
value: [],
writable: false,
enumerable: true
};
literally assigns an object with the properties value, writable and enumerable to this.list.
What you seem to want is:
Object.definProperty(this, 'list', {
value: [],
writable: false,
enumerable: true
});
Now this.list returns an array, but it's not possible to assign a new value to the property.
How to create non-enumerable properties at construction ?
function pp_urlfield( object ) {}
pp_urlfield.prototype = Object.create( Object.prototype, {
type_internal: {
writable: true,
configurable: true,
enumerable: false,
value: ""
},
type: {
get: function() {
return this.type_internal;
},
set: function( value ) {
this.type_internal = value;
}
}
} );
If I construct this object and assign the member "type", the assignment "this.type_internal = value" creates a local and non-enumerable variable :
var a = new pp_urlfield;
a.type = 1;
//Returns ["type_internal"]
Object.keys(a);
I found a partial solution by replacing this.type_internal = value by :
Object.defineProperty(this, "type_internal", { value: value, enumerable: false });
But I think there must be a better solution.
(I don't want to use any framework, e.g. Prototype)
I was looking at the example on the MDN pages about Inheritance Revisited and thought it would be nice to have the doSomething methods actually do something. So I started out with the following code, based on the example:
function A(a) { this.varA = a };
A.prototype = { varA: null, doSomething: function() { console.log('do something with ' + this.varA) } };
function B(a, b) {
A.call(this, a);
this.varB = b;
};
B.prototype = Object.create(new A(), {
varB: { value: null, enumerable: true, configurable: true, writeable: true },
doSomething: { value: function() {
A.prototype.doSomething.apply(this, arguments);
console.log("do something with " + this.varB);
}, enumerable: true, configurable: true, writeable: true}
});
var b = new B('a', 'b');
b.doSomething();
I copy and pasted the code into the Chrome console and expected to be seeing
do something with a
do something with b
but instead I got
do something with a
do something with null
What am I overlooking here? Shouldn't the call to "new B" result in the constructor which was defined above (function B(...)) being called? And if the constructor is called, shouldn't b.varB have a value? How do I need to change the example so the output is as expected?
Accidentally you specified varB as being non-writable and hence the assignment this.varB = b failed (or was ignored).
writeable: true should be spelled writable: true (without e). By default, properties defined using the a property descriptor are non-writable.
So the whole descriptor becomes:
varB: { value: null, enumerable: true, configurable: true, writable: true }
Since you are assigning a value inside the constructor function anyway, you don't really have to use the descriptor though.
More information: MDN - Object.defineProperty.