I have cloned a javascript object using lodash.cloneDeep().
I want to change the value of one of the object properties and just print out for testing purpose. But "this" does not seem to change.
const object = {
id: 'old value',
toString: () => {
console.log(this.id);
},
getThis: () => {
return this;
}
}
const clonedObj = _.cloneDeep(object);
clonedObj.id = 'new value'
console.log(clonedObj.id) // returns "new value"
clonedObj.toString() // returns "old value"
console.log(cloneObj === object) // returns false
console.log(cloneObj.getThis === object) // returns true
Can someone help me understand this.
Related
Is it possible for a JS field decorator to change its value?
A simplified use case would be something like this:
const addItem = (newValue) => {
return function (target) {
target.value.push(newValue);
};
};
class Test {
#addItem(4)
static values = [1,2,3];
}
const test = new Test();
console.log(test.constructor.values) // [1,2,3,4]
Using the following experimental decorators:
'#babel/plugin-proposal-decorators',
{
version: '2018-09',
decoratorsBeforeExport: true,
},
End goal is to make a decorator to inject tailwind style sheets into a lit elements static styles. Currently using a mixin for this but just doing this for fun and to learn whats possible with decorators.
Update to Barmars comments
When trying to return a value from the inner function, I end up getting an error:
export const addItem = (value) => {
return function (target) {
return [value];
};
};
Uncaught TypeError: An element descriptor's .kind property must be either "method" or "field", but a decorator created an element descriptor with .kind "undefined"
Looking at the documentation, the variables getting passed to each of these functions doesn't seem to match either.
function logged(value, { kind, name }) {
if (kind === "field") {
return function (initialValue) {
console.log(`initializing ${name} with value ${initialValue}`);
return initialValue;
};
}
}
When running that example, the 2nd parameter to logged() is undefined. "initialValue" also is an object, not the value:
Object { kind: "field", key: "styles", placement: "own", descriptor: {…}, initializer: value(), … }
Nicolo Ribaudo was able to help me over on Babel's discussions. The correct way to do this is to use the initializer function:
const addItem = (newValue) => {
return function (target) {
const { initializer } = target;
target.initializer = function () {
return [
...initializer.call(this),
newValue,
];
};
};
};
class Test {
#addItem(4)
static values = [1,2,3];
}
const test = new Test();
console.log(test.constructor.values) // [1,2,3,4]
I am practicing JavaScript Proxies and want to access a method from another object but with an empty Proxy object:
const data = {
hello: {
log() {
return 'hello log'
},
},
hi: {
log() {
return 'hi log'
},
},
}
const blankObject = {} // I can just pass the data object but I want an empty one
const proxy = new Proxy(blankObject, {
get(target, key) {
const v = target[key]
if (typeof v === 'function') {
// if data.hello.log() or data.hi.log()
return function() {
return data[key]['WHAT_TO_DO']// access data.hello.log or data.hi.log() here?
}
}
return v
}
})
proxy.hello.log() // hello log;
Basically I'm trying to check if that method property exist in another object. I just want to tell the proxy to get the value from another object without passing it into the constructor.
I don't understand why you want to use a different object than the object you are proxying. It makes little sense to proxy an empty object instead.
Secondly, if you are going to access the hello property of the proxy object, then realise that this hello value -- as found in the data object -- is not proxied, so it is not in this proxy that you should check whether the property is a function. At this point the log property is not accessed yet. It's only about the hello access that the proxy is aware.
But you can divert the path to the data object when hello is accessed, by verifying it is indeed a property of the data object. So:
const data = {
hello: {
log() {
return 'hello log';
},
},
hi: {
log() {
return 'hi log'
},
},
}
const blankObject = {};
const proxy = new Proxy(blankObject, {
get(target, key) {
if (key in data) return data[key]; // <---
return target[key]; // default
}
});
console.log(proxy.hello.log()); // hello log;
still trying to figure out what in the world you are trying to accomplish here. you're trying to add a method from one object, to another object?
const blankObject = { hello: data.hello };
though this feels a bit hacky. would probably be best to just pass the whole data object into the constructor, so that the blank object has a reference to it, and can use its methods whenever it needs to.
Doesn't matters, using a test, no needs to over-engineer!
let data = {
hello: {
log() {
return 'hello log'
},
},
hi: {
log() {
return 'hi log'
},
},
}
let blankObject = {} // I can just pass the data object but I want an empty one
// We test if the object has a given property and return accordingly
console.log(
(blankObject["hello"]) ? blankObject.hello.log() : data.hello.log()
)
var array = [];
Now, I am creating an object with post requests.
var object = {
property 1: req.body.x;
property 2: req.body.y
};
if the property 1 value(i.e. req.body.x) already exists in any of the objects in the array, it should giving a warning. Else we need to do array.push(object).
How to check for the property 1 value every time with the post request.
You can use array.Find in order to check if an object exists in the array with the same property.
const arr = [{
prop1: 'foo', // prop1 of `foo` already in array
}]
// small function so we can avoid code duplication
const existsInArray = (obj) => {
return arr.find((a) => a.prop1 === obj.prop1)
}
const obj1 = {
prop1: 'foo',
}
const obj2 = {
prop1: 'bar',
}
if (existsInArray(obj1)) {
console.warn('obj1 already in array')
} else {
arr.push(obj1)
}
if (existsInArray(obj2)) {
console.warn('obj2 already in array')
} else {
arr.push(obj2)
}
console.log(arr)
I have two inputs:
data = {"year": 2021}
valueAccessor = (d) => d["year"];
These two input can be dynamic, so I do not know what will be in the object or function.
I want create a new object, and set values to that object using the Accessor function. Is there a way to do this?
output = {}
output = definePropertyUsingFunction(output, valueAccessor, newValue)
Short answer is "no". But...
If you're in some sort of controlled learning environment, there are some things you could try.
If you know for a fact that:
Your getter function is pure (no side effects), and
Your getter function always accesses 1 property,
you could
Use a Proxy that tracks property access
Make a call to the getter to trigger it (again, if this is a pure function it should not have any side effects)
Write a value to the logged property
Here's a proof of concept:
const data = { year: 2000, month: 1, day: 28 };
const getYear = obj => obj.year;
const getMonth = obj => obj.month;
const toString = obj => `${obj.year}/${obj.month}/${obj.day}`;
const writeViaSimpleGetter = (obj, value, getter) => {
let propName = null;
const proxy = new Proxy(obj, {
get: (target, key) => {
if (propName) throw "Multiple properties accessed";
propName = key;
}
});
// Call the getter
getter(proxy);
if (!propName) throw "No property accessed";
return { ...obj, [propName]: value };
}
// Simple getters work:
console.log(
writeViaSimpleGetter(data, 2021, getYear)
)
console.log(
writeViaSimpleGetter(data, 12, getMonth)
)
// This throws:
try {
console.log(
writeViaSimpleGetter(data, "oops", toString)
)
} catch(e) { console.log("ERROR:", e) }
// This also throws:
try {
console.log(
writeViaSimpleGetter(data, "oops", () => {})
)
} catch(e) { console.log("ERROR:", e) }
I would like to write a proxy object to automatically print errors when calling some property in original object which is not found.
const proxyObjectFn = () => {
const _obj = Object.assign({}, originalObject);
const get = (key) => {
const value = _obj[key];
if (value === undefined) {
console.error(`${key} not found`);
}
return value;
};
return {
get,
};
};
const proxyObject = proxyObjectFn();
export default proxyObject;
// caller
proxyObject.get('someProperty')
This works, but is there any elegant way so that I can call through proxyObject.someProperty instead of proxyObject.get('someProperty')?
Update
Let me make it more specific. Actually I am writing a translation object.
Original object may be from json, like { "HELLO_KEY": "Hello World" }. I am to call like { label: _t.SOME_I18N_KEY } in UI display code, assuming _t is the proxy object above. I can print the warning to tell me there is missing translation.
You can use the Proxy object:
const handler = {
get: (obj, prop) => {
if(!obj.hasOwnProperty(prop)) console.error(`${prop} not found`);
return obj[prop];
}
};
const _t = new Proxy({ "HELLO_KEY": "Hello World" }, handler);
console.log(_t.HELLO_KEY);
console.log(_t.SOME_NONEXISTENT_KEY);