class Testone{
constructor(value){
Object.defineProperty(this, 'doSomething', {
enumerable: false,
configurable: false,
writable: false,
value: () => {
//do whatever
}
});
}
}
const doWhatever = () => {
//do whatever
}
class Testtwo{
constructor(value){
Object.defineProperty(this, 'doSomething', {
enumerable: false,
configurable: false,
writable: false,
value: doWhatever
});
}
}
My thought is that Testtwo should be more efficient, since doWhatever would only exist in memory once then get pointed to by every instance of Testtwo. Testone would instantiate a new anonymous function for each new instance.
Does Testone actually create a new anonymous function each time? Is Testtwo therefor more efficient or is it also creating separate instances of doWhatever?
Am I missing some major caveat to one over the other (other than variable scope)?
My benchmarking consistently shows ~2% difference in instantiation time, with Testtwo indeed being faster... but that's not exactly confirmation.
Yes. Testone create new doSomething function every time, but Testtwo uses existing one.
Proof:
class Testone{
constructor(value){
Object.defineProperty(this, 'doSomething', {
enumerable: false,
configurable: false,
writable: false,
value: () => {
//do whatever
}
});
}
}
const doWhatever = () => {
//do whatever
}
class Testtwo{
constructor(value){
Object.defineProperty(this, 'doSomething', {
enumerable: false,
configurable: false,
writable: false,
value: doWhatever
});
}
}
const f1 = new Testone()
const f2 = new Testone()
console.log('Testone', f1.doSomething === f2.doSomething)
const s1 = new Testtwo()
const s2 = new Testtwo()
console.log('Testtwo', s1.doSomething === s2.doSomething)
Related
I have the following code:
Object.defineProperty(Object.prototype, 'json', {
configurable: true, enumerable: false, writable: true,
value: function() { return 'Object.json' }
});
function Body() {
return 1
}
Object.defineProperty(Body.prototype, 'json', {
configurable: true, enumerable: false, writable: true,
value: function() { return 'Body.json' }
});
console.log(Body.json())
which, when I run I get an unexpected result:
Object.json
I gather that a function is an object, in the loosest sense of the word (because typeof will return different values) and that therefore, functions may inherit from objects, but if a function is derived from object, I would expect its properties to override or hide those of the base class. yet, the result shows otherwise
how can this be and how can I get the property defined on the function to override that defined on object?
When you call Body.json(), you're not calling json() on an "instance" of Body, but on Body itself, which inherits from the Object prototype.
If you define the property on Body itself, it will take precedence when evaluating your Body.json() call:
Object.defineProperty(Object.prototype, 'json', {
configurable: true, enumerable: false, writable: true,
value: function() { return 'Object.json' }
});
function Body() {
return 1
}
Object.defineProperty(Body, 'json', {
configurable: true, enumerable: false, writable: true,
value: function() { return 'Body.json' }
});
console.log(Body.json()); // "Body.json"
Alternatively, if you define the property on the Body prototype and invoke the method on an instance of Body, you will also get the expected result:
Object.defineProperty(Object.prototype, 'json', {
configurable: true, enumerable: false, writable: true,
value: function() { return 'Object.json' }
});
function Body() {
return 1
}
Object.defineProperty(Body.prototype, 'json', {
configurable: true, enumerable: false, writable: true,
value: function() { return 'Body.json' }
});
console.log(new Body().json()); // "Body.json"
Basically just want to create a new hashmap once the window is closed because it currently will still have the old values after closing and rendering a new window.
data: {
classCheck: false,
hashTable: new Ext.util.HashMap(),
countValid: 0
}
listeners: {
afterrender: function() {
var scope = this;
window.addEventListener('resize', function() {
scope.updateWindow(scope);
});
this.on('close', function(scope) {
this.getViewModel().data.hashTable = new Ext.util.HashMap();
window.removeEventListener('resize', scope.updateWindow);
});
},
},
renderer: function(value, cell_field1, cell_field2, cell_field3) {
var hashmap = this.up('classroom').getViewModel().data.hashTable;
JavaScript uses prototyping to implement class inheritance. The windows are instances of a window class, and due to the nature of prototyping the window instances reference the properties defined on the class until an instance explicitly sets them.
Ext.define('Fiddle.Class', {
boolean: true,
object: {},
constructor: function() {
/* 1. Instance Prototype
{ {
boolean: true,
object: {}
} }
*/
this.boolean = false;
this.object.key = false;
this.object = {};
/* 2. Instance Prototype
{ {
boolean: false, boolean: true,
object: { key: true } object: { key: false },
instance: null
} }
*/
// This returns true.
return this.object.key;
}
});
Therefore, the window instances need to set the values of properties that are objects or arrays during initialization, so that each instance gets its own copy. This can be defined on the class, and it is usually done in the constructor so that the data is available as early as possible.
Ext.define('Fiddle.window.Window', {
extend: 'Ext.window.Window',
data: null,
constructor: function(config) {
this.data = {
classCheck: false,
hashTable: new Ext.util.HashMap(),
countValid: 0
};
this.callParent(arguments);
}
});
i'm trying to watch an objects value, and if it changes, so some stuff..
So this is my object,
var list = [{
object: undefined,
index: 0,
src: 'url here',
active: { val: 0 }
}]
So I made active an additional object as I create a new object from the above, but make the active value the value from above, this keeps a reference of this object between the 2 objects.
var newList = [];
newList.push({
object: undefined,
index: 0,
src: list[i].src,
active: list[i].active // Use reference to old list
});
So i'm trying to watch the active value like so:
(list.active).watch('val', function() {
if (list.active.val === 1) {
console.log('active');
list.object.classList.add('active');
} else {
console.log('not active');
list.object.classList.remove('active');
}
});
However it appears that when I watch this value it is being removed, as if I console.log out the list, then the value is set to undefined! I'm changing the value of list.active.val after adding the watch events.
Here is the Polyfill i'm using for the watch functionality.
// object.watch
if (!Object.prototype.watch) {
Object.defineProperty(Object.prototype, "watch", {
enumerable: false,
configurable: true,
writable: false,
value: function (prop, handler) {
var oldval = this[prop],
newval = oldval,
getter = function () {
return newval;
},
setter = function (val) {
oldval = newval;
return newval = handler.call(this, prop, oldval, val);
};
if (delete this[prop]) { // can't watch constants
Object.defineProperty(this, prop, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
}
});
}
// object.unwatch
if (!Object.prototype.unwatch) {
Object.defineProperty(Object.prototype, "unwatch", {
enumerable: false,
configurable: true,
writable: false,
value: function (prop) {
var val = this[prop];
delete this[prop]; // remove accessors
this[prop] = val;
}
});
}
Edit 1
Added the proxy-observe Polyfill however this doesn't appear to be watching still, I have added it like so:
list[0] = Object.observe(list[0], function(changeset) {
console.log('changed');
});
list[0].active contains the object { val: 0 }, so it should be observicing this object.
Not getting any errors, it's just doing nothing, ideas?
You don't need to implement a custom watch/unwatch features,
Ecmascript 2015 already provides a specific api:
Proxy
There are a plenty of polyfills to make it working on legacy browsers.
There was a proposal called Object.Observe to address what you need and you can find a Proxy porting here: https://github.com/anywhichway/proxy-observe
Follows a basic working example:
// Your Observable target
const target = Object.create(null);
const observer = {
set(target, key, value) {
console.log(`Should we set '${value}' as value of '${key}' property?`)
target[key] = value;
},
};
const observable = new Proxy(target, observer);
observable.someKindOfProperty = 'Hello World';
I've a scenario where I need to modify a property of a class using Object.defineProperty(). I know it can be done through the get() of the descriptor.
If you see the example below, I'm trying to return a function which when called will return a value from this.
My question is, do I need to define that property again for the this object? Is it necessary? If yes, why?
When I define a property to a class, this will also reflect the same right?
I came through this and I'm curious to know why he is doing this.
class A {
constructor() {
this.h = 'hello world'
}
hello() {}
}
const des = Object.getOwnPropertyDescriptor(A.prototype, 'hello')
Object.defineProperty(A.prototype, 'hello', {
configurable: true,
get: function(){
//is this necessary
Object.defineProperty(this, 'hello', {
configurable: true,
value: () => this.h,
})
//
return () => this.h
}
})
const n = new A()
console.log(n.hello())
I have no idea why that person is doing this. I probably wouldn't do it. But if your question is whether there is a difference in doing it or not, the answer is yes.
class A {
constructor() {
this.h = 'hello world'
}
hello() {}
}
const des = Object.getOwnPropertyDescriptor(A.prototype, 'hello')
Object.defineProperty(A.prototype, 'hello1', {
configurable: true,
get: function() {
Object.defineProperty(this, 'hello1', {
configurable: true,
value: () => this.h,
});
return () => this.h;
}
});
Object.defineProperty(A.prototype, 'hello2', {
configurable: true,
get: function() {
return () => this.h;
}
});
const n = new A()
console.log(n.hello1); // () => this.h OK
console.log(n.hello2); // () => this.h OK
Object.setPrototypeOf(n, null);
console.log(n.hello1); // () => this.h Still OK
console.log(n.hello2); // undefined Oops!
It's also possible that calling a getter may be more expensive than reading a data property.
Fiddle
var Assertion = function() {
return { "dummy": "data" };
}
Object.defineProperty(Object.prototype, 'should', {
set: function(){},
get: function(){
return new Assertion(this);
}
});
// Insert magic here.
// This needs to be false
console.log(({}).should === undefined);
What options do I have in ES5 to undo a defineProperty call ?
No silly suggestions like Object.defineProperty = function() { } please.
The following Object.defineProperty(Object.prototype, 'should', {})
does not work
and Object.defineProperty(Object.prototype, 'should', { value: undefined })
Throws a Uncaught TypeError: Cannot redefine property: defineProperty in V8
Object.defineProperty(Object.prototype, 'should', {
set: function() {},
get: function() { return undefined; }
});
Throws the same error
delete Object.prototype.should also does not work
In general, you can't undo a defineProperty call, since there's no undo stack or something. The JS engine does not keep track of previous attribute descriptors.
For example,
Object.defineProperty(Object.prototype, 'foo', {
configurable: true,
value: 1,
enumerable: false
});
Object.defineProperty(Object.prototype, 'foo', {
get: function () {
alert('You cannot revert me');
return 2;
},
enumerable: true
});
What you can do is remove or reconfigure an attribute, or overwrite its value. As mentioned in the other answer, the configurable flag is required to be true if you want to remove or reconfigure.
Once a property is defined with configurable:false, you cannot change the configurable flag.
To remove an attribute (this is supposedly what you want to do), use delete:
Object.defineProperty(Object.prototype, 'foo', {
configurable: true, // defaults to false
writable: false,
value: 1
});
delete Object.prototype.foo;
console.log(Object.prototype.hasOwnProperty('foo')); // false
To reconfigure, use defineProperty again and pass a different descriptor:
Object.defineProperty(Object.prototype, 'foo', {
configurable: true,
get: ...
set: ...
});
Object.defineProperty(Object.prototype, 'foo', {
value: undefined
});
console.log({}.foo); // undefined
console.log(Object.prototype.hasOwnProperty('foo')); // true
As shown in this sample, you can use defineProperty to switch between accessor (get/set) and data (value) properties.
To overwrite, use simple assignment. In this case, you need the writable flag to be true. Obviously this does not work with accessor properties. It even throws an exception:
Object.defineProperty(Object.prototype, 'foo', {
configurable: true,
value: 1,
writable: true // defaults to false
});
Object.prototype.foo = undefined;
console.log(Object.prototype.foo); // undefined
console.log(Object.prototype.hasOwnProperty('foo')); // true
Object.defineProperty(Object.prototype, 'foo', {
get: function () {
return 1;
},
writable: true // JS error!
});
Note that writable defaults to false when you use defineProperty, but true when you use the simple syntax o.attr = val; to define a (previously not existing) property.
If you want to undo your last defineProperty or all of them, you can use this class:
(gist here)
class PropertyDescriptorStack {
private readonly descriptors: PropertyDescriptor[] = [];
constructor(private readonly target: Object, private readonly prop: string) {
if (!target || typeof prop !== "string") { // your choice to define ""
throw new Error("PropertySaver: no object or property");
}
}
public push(props: Partial<PropertyDescriptor>): boolean {
this.saveDescriptor(this.target, this.prop);
try {
Object.defineProperty(this.target, this.prop, {
...props,
configurable: true,
});
return true;
}
catch (e) {
console.error(`Error setting property ${this.prop} on ${this.target}: ${e}`);
return false;
}
}
public pop(toStart?: boolean): boolean {
const ind = toStart ? 0 : this.descriptors.length - 1;
const descriptor = this.descriptors[ind];
if (!descriptor) {
return false;
}
this.descriptors.splice(ind, this.descriptors.length - ind);
try {
Object.defineProperty(this.target, this.prop, descriptor);
return true;
}
catch (e) {
console.error(`Error resetting property ${this.prop} on ${this.target}: ${e}`);
return false;
}
}
/**
* Saves the current descriptor of the property in the object in the descriptors stack.
* The descriptor is taken either from the object or from the closest prototype that has this prop.
* If none is found, a new descriptor is generated with the current value.
* #param target
* #param prop
* #returns The found descriptor
*/
private saveDescriptor(target: object, prop: string): PropertyDescriptor {
let ds: PropertyDescriptor | null = null;
for (let o: any = target, ds: PropertyDescriptor = null; o; o = Object.getPrototypeOf(o)) {
ds = Object.getOwnPropertyDescriptor(o, prop);
if (ds) {
break;
}
}
ds = ds || {
configurable: true,
writable: true,
value: target[prop],
enumerable: true
}
this.descriptors.push(ds);
return ds;
}
}