I'm trying to delete an object property:
var test = {abc: 1};
console.log(delete test.abc); //works fine and returns 'true'
The following construct drives me crazy
function deleteNode(_node) {
console.log(delete _node);
}
deleteNode(test.abc); // does not work and returns 'false'
Why? I read many questions on stackoverflow regarding trouble with delete and read most of the typical links provided. But I can't find a solution to this simple problem...
Deleting dynamic props of an object could be achieved like this:
function deleteNode(obj, key) {
delete obj[key]
}
See the delete docs for more details.
When having a "path" like "a.b.c" you can use lodash unset which deletes nested entries:
var object = { 'a': { 'b': { 'c': 7 } } };
_.unset(object, 'a.b.c');
Use of eval is discouraged .
var test = {abc: 1};
function deleteNode(_node) {
console.log(delete _node);
}
deleteNode(test.abc);
When you invoked deleteNode above, test.abc already resolved to 1 before being passed to function. deleteNode is technically invoking delete 1. And according to ES standard, deleting a function argument directly results in false or gives an error in strict mode.
"use strict";
var test = {a: 1};
function del(a) {
console.log(delete a);
}
del(test.a);
You will need to pass the object and key as different arguments to method.
var test = {abc: {a: 1, b: 2, c: {d: 1}}};
function deleteNode(obj, key) {
console.log(eval('delete obj.' +key));
}
deleteNode(test, 'abc.c.d');
console.log('test is', test)
Related
This is a bit of a tricky question regarding ES6 destructuring with default usage in a javascript object constructor.
I would like to receive a destructured parameters object with default values for my object constructor
so what i did was this
function bla({a=3,b=6}={}){
this.a=a;
this.b=b;
console.log(`this.a::'${this.a}' this.b::'${this.b}' a::'${a}' b::'${b}'`);
}
let myObject= new bla({a:1});
console.log(`myObject.a::'${myObject.a}' myObject.b::'${myObject.b}'`); // only a got overriden with value "1" and b remained its defauly value "6"
I know that what i did works. However, you can see that this is a bit of a code smell, because every time i need to add a new parameter to the constructor (for example {newParameter=3}) i also need to go down and add a matching line like this in the constructor body
this.newParameter=newParameter;
Is there any more elegant way to add a destructured parameter with default value which automatically is attached to "this."
I personally think your current approach is the most readable, but you can technically also do
function bla(obj = {}){
({
a: this.a = 3,
b: this.b = 6,
} = obj);
console.log(`this.a::'${this.a}' this.b::'${this.b}'`);
}
Don't know if this is best, but you could use Object.assign.
function bla(props={}) {
Object.assign(this, {a:3,b:6}, props);
console.log(`this.a::'${this.a}' this.b::'${this.b}'`);
}
let myObject= new bla({a:1});
console.log(`myObject.a::'${myObject.a}' myObject.b::'${myObject.b}'`); // only a got overriden with value "1" and b remained its defauly value "6"
You lose the parameter names, but it could be argued that this is better so that you don't accidentally mutate the parameter when you meant to mutate the object property.
I follow more a functional style to avoid the new on object creation and this keyword.
Explanation
You could simply write a function that retuns an object and takes several arguments with default values.
Thanks of the object literal property value shorthand you have less to write.
Code
function returnObject(a = 1, b = 2, c = 3) {
return {
a,
b,
c
}
}
console.log(returnObject())
If the objective is to use the variable names exactly once then this is what I'd do:
const foo = new Foo({ a: 1 });
console.log(`foo { a: ${foo.a}, b: ${foo.b} }`);
function Foo(config = {}) {
const defaults = { a: 3, b: 6 };
for (const [key, val] of Object.entries(defaults))
({ [key]: this[key] = val } = config);
}
Now, you only need to update the defaults object and you're done.
Actually, let's make a constructor constructor by abstracting this pattern:
const Foo = defcons({ a: 3, b: 6 });
const foo = new Foo({ a: 1 });
console.log(`foo { a: ${foo.a}, b: ${foo.b} }`);
function defcons(defaults) {
return function (config = {}) {
for (const [key, val] of Object.entries(defaults))
({ [key]: this[key] = val } = config);
};
}
Now, you can easily create as many such constructors as you want.
I'm trying to create a custom logger which just wraps a console.log but always adds something to the start which makes it absolutely clear that the log is coming from my plugin.
I have come up with the following code:
var log = function(param1, param2) {
if (typeof param3 !== 'undefined') {
console.log('[MyPlugin]', param1, param2, param3);
} else if (typeof param2 !== 'undefined') {
console.log('[MyPlugin]', param1, param2);
}
};
This allows the developer to run the following:
log('foo', 'bar');
// Outputs '[MyPlugin] foo bar'
log('foo');
// Outputs '[MyPlugin] foo'
But I hope that this can be improved upon.
The issues with this implementation are:
The logging function only allows two parameters. It would be better if it could accept many.
There's lots of repetition (multiple console.log calls).
What I have tried.
I thought maybe the ES6 spread-operator would work:
var log = function(...params) {
console.log('[MyPlugin]', params);
};
Which allows the developer to run:
log('foo', 'bar');
// Outputs '[MyPlugin] Array [ "foo", "bar" ]'
log('foo');
// Outputs '[MyPlugin] Array [ "foo" ]'
You can see that the output is not the same as in the original function.
Is there a better solution?
Spread notation (it's not an operator) would indeed do it, if you were using it. You're using rest notation (to gather arguments into an array parameter), but not spread notation (to spread them out when passing them to console.log). Here's how you'd use spread:
var log = function(...params) {
// Rest -----------^^^
console.log('[MyPlugin]', ...params);
// Spread ----------------^^^
};
Example:
var log = function(...params) {
// Rest -----------^^^
console.log('[MyPlugin]', ...params);
// Spread ---------------^^^
};
log("testing", 1, 2, 3);
If you need to support pre-ES2015 environments without transpiling, you can do the same thing with arguments and Function#apply:
var log = function() {
var args = Array.prototype.slice.call(arguments);
args.unshift('[MyPlugin]');
console.log.apply(console, args);
};
Live Example:
var log = function() {
var args = Array.prototype.slice.call(arguments);
args.unshift('[MyPlugin]');
console.log.apply(console, args);
};
log("testing", 1, 2, 3);
I am currently using the object destructuring pattern with default parameters described in that answer to ES6 Object Destructuring Default Parameters.
(function test({a = "foo", b = "bar"} = {}) {
console.log(a + " " + b);
})();
I would like to be able to access the object parameter without assigning it to a variable in the function body and explicitly listing each key.
(function test({a = "foo", b = "bar"} = {}) {
const options = {a, b};
console.log(options);
})();
I tried naming the object argument, but the function looses the ability to resolve missing keys to their default value.
(function test(options = {a = "foo", b = "bar"} = {}) {
console.log(options);
})();
It seems to be ignoring the default parameters when destructuring into a named argument.
Is this part of the ES6 spec? Is there a way to achieve the desired behavior without additional code in the function body?
Edit: I removed a superfluous example that did not add context to the question.
Honestly, I think you're overcomplicating this. Default parameters are not compulsory -- in this case your code can be cleaner without it.
I would simply take the object options as the parameter and do the destructuring within the body of the function, after assigning default values.
function test(options) {
options = Object.assign({a: 'foo', b: 'bar'}, options);
let {a, b} = options;
console.log(options, a, b);
}
test(); // foo bar
test({a: 'baz'}); // baz bar
test({b: 'fuz'}); // foo fuz
test({c: 'fiz'}); // foo bar
With particular regard to your final snippet:
(function test(options = {a: "foo", b: "bar"}) {
console.log(options);
})({a: "baz"});
The problem is that a default parameter is used when the value passed is undefined. Here, the value passed is {a: "baz"}. That is not undefined, so the default parameter is ignored. Objects are not merged automatically.
More broadly in answer to your question: there is no way of getting both an object and destructuring some of its properties in the parameters of a method. Frankly, I'm grateful, because function signatures can be hard enough to read at first glance as it is.
I am copying functions from one object to another. The problem is that while they are anonymous in the source object, they have a name in the target object:
var o1 = {
a: function() {
alert("Hello World");
},
b: 123,
c: "Some string"
}
var o2 = {};
for (var key in o1) {
if ("function" == typeof o1[key]) {
o2[key] = o1[key];
}
}
console.log(o2.a); //output: function o1.a()
The two functions do not seem to be connected in some way, but this is very irritating at least. Also, Firefox Developer Edition knows where the function came from if I log it in the console and click the name. And I don't know whether this might have some other bad influence somehow.
So, if it is possible to copy a function and keep it anonymous, that would be great!
You can use Object.assign().
var o1 = {
a: function() {
alert("Hello World");
},
b: 123,
c: "Some string"
}
var o2 = Object.assign({}, o1);
For manipulate independents objects.
Look this too:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
let us say i have a object in which there is a function and inside the function i have declared some key values.
if every function is an function object in javascript then it is totally legal to declare key value pair in it.
var a ={
a: "shiv",
b: "shiv1",
c: function(){
L:"shiv1",
console.log(L);
}
}
how can i access these keys. in what scenarios i need to add key value pairs to a function. what does this signify. For Example in this function, how can i access L key.
Edit 1:
Console.log line will through err.
let say we have only this code
var a ={
a: "shiv",
b: "shiv1",
c: function(){
L:"shiv1",
}
}
what does declaring a key in function signify. if i need to access L key how can i
You every function is also an object, meaning that you can indeed set properties to it. In fact every function has length property, which denotes the number of formal arguments this function accepts.
However the syntax you are using to set function properties is not how you should do it. Even though you are using perfectly valid syntax, this is label statement, not property definition syntax. If you wanted to set a property to a function object in your case you would do it like this:
function c() {
console.log(c.L) // => "I'm a property of c function"
}
c.L = "I'm a property of c function";
var a = {
a: "shiv",
b: "shiv1",
c: c
}
When it can be useful? Like I said there is a limited use for it, like length property of the function, but in many cases you would not need setting properties on a function level directly.
This has to be throwing errors:
L:"shiv1",
console.log(l);
You probably want:
c: function(){
return {L:"shiv1"};
}
And then access it as:
a.c().L;
Full example here:
var a ={
a: "shiv",
b: "shiv1",
c: function(){
return {L:"shiv1"}
}
}
alert(a.c().L);
You can't declare keys like you did inside the function.
This doesn't work:
c: function(){
L:"shiv1", //Declaration don't work in this context
console.log(l); //Don't work
}
Try this (Please, remove the "function" statement):
c: {
L:"shiv1"
}
Also, you can do this:
c: function() {
var test = "shiv1";
return test;
}
If you want to work with parameters:
c: function(a, b) {
var test = a + " shiv1 " + b;
return test;
}
Or:
c: function(a, b) {
var total = a + b;
return total;
}