Hi, I am trying to transform an object into a proxy, without changing the reference to the object:
Here is a simple class:
class Foo {
constructor () {
this.a = 'bar'
}
}
const foo = new Foo()
Here is my Proxy:
const proxy = new Proxy(foo, {
get () {
return 'proxy-bar'
},
set () {
// Don't do anything
return true
}
})
Here is what a normal use of this proxy does:
console.log(foo.a) // bar
console.log(proxy.a) // proxy-bar
Now, I want to keep using foo, but with the capabilities of proxy. So I tried to use Object.assign which seems to work only for the getter, but not for the setter. Is their something I miss?
Object.assign(foo, proxy)
console.log(foo.a) // Getter works: proxy-bar
foo.a = 'proxy-proxy-bar'
console.log(foo.a) // Setter does not work: proxy-proxy-bar
You can apply the proxy in your constructor and return it :
class Foo {
constructor() {
this.a = 'bar';
return new Proxy(this, {
get() {
return 'proxy-bar'
},
set() {
// Don't do anything
return true
}
});
}
}
const foo = new Foo();
foo.a = 'proxy-proxy-bar';
console.log(foo.a); // proxy-bar
Related
I can defined readFoo in Foo class:
var myFormat = 'foo'
class Foo {
[ "read" + ((format) => format)(myFormat) ]() {
return 123;
}
}
is there any way how to define function base on config like:
var config = ['foo1', 'foo2']
class Foo {
config.map((name) => {
[ "read" + ((format) => format)(name) ]() {
return 123;
}
}
}
Will create functions readFoo1 and readFoo2.
You can iterate through the array and assign to the prototype afterwards:
var config = ['foo1', 'foo2']
class Foo {}
for (const name of config) {
Foo.prototype["read" + name] = function() {
return 123;
};
}
const f = new Foo();
console.log(f.readfoo1());
I have a Javascript module:
const myModule = {
foo: this.initializeFoo(),
initializeFoo(){
// some loops and stuff to create an array
}
}
But I get an error: this.initializeFoo is not a function.
Is there some syntax I need to use to make this work, or is it not possible?
If you only intend to call it once and at the object's creation, then I would opt for a self-executing anonymous function:
const myModule = {
foo: (function () {
// some loops and stuff to create an array
})()
};
Alternatively, you can use arrow syntax instead:
const myModule = {
foo: (() => {
// some loops and stuff to create an array
})()
}
Example snippet:
const myModule = {
foo: (() => {
console.log('Processing');
return Array.apply(null, {length: 10}).map(Number.call, Number);
})()
};
// You can see that 'Processing' is only printed once
console.log(myModule.foo[2]);
console.log(myModule.foo[7]);
Declare the initializeFoo() function in outside of the Object
const myModule = {
foo : initializeFoo(),
}
function initializeFoo(){
return 'hi';
//or some loops and stuff to create an array
}
console.log(myModule)
If you can use ES6:
class MyModule {
constructor() {
this.initializeFoo();
}
initializeFoo() {
console.log('test');
// some loops and stuff to create an array
}
}
const myModule = new MyModule();
If you need to store the result of initializeFoo():
class MyModule {
constructor() {
this.initializeFoo();
}
initializeFoo(){
console.log('test');
this.initialVal = 2;
}
}
const myModule = new MyModule();
// 'test'
myModule.initialVal
// 2
I'm fairly new to getters and setters and am looking for a way to listen for changes in an object to store the data immediately, without calling a Save() function everytime a value gets changed. This is how I do it right now:
var myObject = {
Data: {
enabled: true,
show: false
},
Save: function () {
//store myObject.Data to local storage
},
Load: function () {
//load data from local storage and assign it to myObject.Data
},
doSomething: function () {
myObject.Load();
if (myObject.Data.enabled) {
myObject.Data.show = true;
myObject.Save();
}
}
Now I would like to optimize this code so everytime a property in myObject.Data is changed, myObject.Save() is executed. The problem I'm experiencing is that it seems only possible to define a getter for a property that has just one value, but not for a property that is an object itself.
var myObj = {
_Data: {
a: 0,
b: 1,
c: 3
},
set Data (a) {
console.log(a);
}
};
myObj.Data.a = 2;
This obviously doesn't work since myObj.Data is not an object and doesn't have the same properties as myObj._Data.
Thanks in advance for any help.
You are likely interested in the Proxy object.
I used a very simple debounce function callHandler in order to avoid calling the onSet method dozens of times during array modifications. Otherwise, [1, 2, 3].splice(0, 1) would call the set handler once per item in the original array.
'use strict';
var myObject = {
Data: {
a: [1, 2, 3],
b: {c: ['test']}
},
Save: function() {
console.log('Save called');
},
}
function recursiveProxy(target, onSet) {
// For performance reasons, onSet will only be called one millesecond
// after the set handler has last been called.
var timeout;
function callHandler() {
clearTimeout(timeout);
timeout = setTimeout(onSet, 1);
}
var recursiveHandler = {
get: function(target, property) {
// If the property is something that could contain another object,
// we want to proxy it's properties as well.
if (typeof target[property] == 'object' && target[property] != null) {
return new Proxy(target[property], recursiveHandler);
}
return target[property];
},
set: function(target, property, value) {
console.log('Set called - queueing onSet');
callHandler();
target[property] = value;
return true;
}
}
return new Proxy(target, recursiveHandler);
}
myObject.Data = recursiveProxy(myObject.Data, myObject.Save);
myObject.Data.a.splice(0, 1);
myObject.Data.b.c[0] = 'test 2';
I believe you are looking for Defining a getter on existing objects using defineProperty
To append a getter to an existing object later at any time, use
Object.defineProperty().
var o = { a:0 }
Object.defineProperty(o, "b", { get: function () { return this.a + 1; } });
console.log(o.b) // Runs the getter, which yields a + 1 (which is 1)
For e.g:
var Data = {
enable: true,
show: false
};
Object.defineProperty(Data, 'doSomething', {
get: function() {
// get something;
},
set: function(something) {
// set something
}
});
I have a factory with a getter and setter
.factory('myService', function() {
var car = null;
return {
car: car,
get: function get() {
return car;
},
set: function set(newCar) {
car = newCar;
}
};
});
I am writing test for it but I cannot call the set method and have it actually set car to newCar
myService.set = sinon.spy();
myService.get = sinon.spy()
it('should set car to new car', function () {
var newCar = ['a','b','c'];
expect(myService.car).toEqual(null); //pass
myService.set(newCar);
dump(myService.car); //null
expect(myService.set).toHaveBeenCalledWith(newCar);//pass
expect(myService.get).toHaveReturned(newCar);//fail
});
Any advice on what I am doing wrong here?
There are more problems here.
One is that the .car property will always be null.
var car = null;
return {
car: car,
get: function get() {
return car;
},
set: function set(newCar) {
car = newCar;
}
};
Here you initialize it with car which is null. There will be no reference between them. This will always be null since you never change that property on the object:
dump(myService.car); //null
You might do something like:
return {
car: null,
get: function get() {
return this.car;
},
set: function set(newCar) {
this.car = newCar;
}
};
But with this you might run into some this context issues later. Why are you trying to expose car if you have a getter for it?
The other thing is that you replace the entire get and set functions with this:
myService.set = sinon.spy();
myService.get = sinon.spy();
Sinon knows nothing about your original get and set.
You should do it like this:
sinon.spy(myService, 'set');
So sinon can wrap your function with a spy while preserving it's original behavior. Check Sinon documentation
I'm intending to write a module that can be instantiated with default configuration and then overridden with custom configuration when initialized. The configuration object has nested objects, so I need to traverse over these nested objects if they are included in the custom configuration. I am attempting to do so by calling customize recursively. This works for the first nested object but the traversal ends after that object. Why is this and what can I do to fully traverse an object containing nested objects?
function Config(options) {
function customize(conf) {
if (conf && conf.constructor === Object) {
for (var prop in conf) {
if(conf[prop].constructor === Object) {
return customize.call(this[prop], conf[prop]);
} else {
if (this.hasOwnProperty(prop)){
this[prop] = conf[prop];
}
}
}
} else {
console.error('The first argument must be an object.');
return;
}
}
//Default config values
this.foo = 'default';
this.bar = {
foo: 'default'
};
this.baz = {
foo: 'default'
};
//Overide default config with custom config
if (options && options.constructor === Object) {
customize.call(this, options);
}
}
function TestModule(){
this.init = function(options){
this.config = (options && options.constructor === Object) ? new Config(options) : new Config();
return this;
};
}
console.log(
new TestModule().init({
foo: 'custom',
bar: {foo: 'custom'},
baz: {foo: 'custom'}
}).config
);
//RESULT
// {
// foo: 'custom',
// bar: {foo: 'custom'},
// baz: {foo: 'default'}
// }
This line:
return customize.call(this[prop], conf[prop]);
occurs inside a for loop, so you are returning before each item has been iterated over. Your return statement should be outside the loop.