In the source code of serve-static npm library I have seen the following line
options = merge({}, options)
where merge function is from utils-merge library and it has exactly the following body
exports = module.exports = function(a, b){
if (a && b) {
for (var key in b) {
a[key] = b[key];
}
}
return a;
};
What is the sense of options = merge({}, options) statement since it just joins options object with an empty object?
What is the sense of options = merge({}, options) statement since it just joins options object with an empty object?
To do exactly that. It copies all properties into a new object, where they cannot be modified anymore even if the caller of serveStatic still holds a reference to the options object he passed.
However, avoiding that the caller messes with the object is not the only reason for detaching it. If we read on, we see things like
delete options.setHeaders
options.maxage = options.maxage || options.maxAge || 0
options.root = root
so we also want to avoid messing with the object that was passed to us. Mutating your arguments is an antipattern.
merge({}, options) creates the new object which has the same attributes as source object (so it is the simplest way to clone JS object). But if you don't pass an empty object as the destination object to merge function or just skip this line, all changes on options object inside serveStatic() function will affect external object what passed to function serveStatic().
Here is the detailed explanation of this nuance of JavaScript language: https://stackoverflow.com/a/3638034/1806421
Related
I am having trouble maintaining the original value of a variable after making new changes to the original variable.
Code:
(...)
data = Illumination.calculate_N(data)
data = Illumination.calculate_pi(data)
data = Illumination.calculate_kwh(data)
data = Illumination.calculate_ca(data)
let data_base = data
let ca_base = data.ca
let kwh_base = data.kwh
let pi_base = data.pi
(...)
data = Illumination.calculate_N(data)
data = Illumination.calculate_pi(data)
data = Illumination.calculate_kwh(data)
data = Illumination.calculate_ca(data)
let data_proposto = data
let ca_proposto = data.ca
let kwh_proposto = data.kwh
let pi_proposto = data.pi
-----------------------------------
EXAMPLE:
static calculate_ai(data){
data.ai = data.areaTotal*data.au
return data
}
It was expected that the original variable (date) would have its values changed, and this happens correctly, however, the variables data_base and data_proposto are not keeping their values
Both variables at the end of the calculation have the same values as the variable date
The variables ca_proposto, ca_base, and the like store their values correctly
Any idea?
The only interactions of the variables data_base and data_proposto were their creations with the data variable and their return of the function
OBS: If I use console.log () to view the value of the data_base variable before redoing the new calculations (Illumination.calculate_N (data)), the value of the variable appears correctly as it should, it is changed shortly after these calculations.
Because in both cases you are assigning not the object itself in the current state, but a reference to that object. What you need to do is to clone the object so the state is frozen at that point.
Simple Clone (Shallow Copy)
let data_base = Object.assign({}, data); //you get a clone of data
let data_proposto = Object.assign({}, data);
The limitation here is that it only does a shallow copy. See Deep Copy below for further explanation.
JSON Clone
This is a quick-and-dirty way to clone as it converts a JSON object to a string, and then back. i.e. you are no longer getting a reference, but a new object.
let data_base = JSON.parse(JSON.stringify(data));
let data_postero = JSON.parse(JSON.stringify(data));
But this won't work if your object is not JSON-safe.
Deep Copy
The least elegant method is probably safest. It deep copies the properties over into a new object. The key difference with Object.assign() is that it copies the values of nested properties, whereas Object.assign() copies the reference to nested objects.
So with Object.assign() any subsequent changes in your nested objects will affect all versions of your "clones". This won't happen if your clones only have property values of those nested objects at the time of cloning – these values are not affected by any changes to the nested objects.
const deepCopy = function(src) {
let target = {};
// using for/in on object also returns prototype properties
for (let prop in src) {
// .hasOwnProperty() filters out these prototype properties.
if (src.hasOwnProperty(prop)) {
target[prop] = src[prop]; //iteratively copies over values, not references
}
}
return target;
}
let data_base = deepCopy(data);
let data_postero = deepCopy(data);
#chatnoir Defined the problem very well, But I do not agree with his JSON serialization solution due to the below probleam:
You will lose any Javascript property that has no equivalent type in
JSON, like Function or Infinity. Any property that’s assigned to
undefined will be ignored by JSON.stringify, causing them to be missed
on the cloned object.
My suggestion to perform deep copy is to rely on a library that’s well
tested, very popular and carefully maintained: Lodash.
Lodash offers the very convenient clone and deepclone functions to perform shallow and deep cloning.
Lodash has this nice feature: you can import single functions separately in your project to reduce a lot the size of the dependency.
Please find the running sample code here: https://glitch.com/edit/#!/flavio-lodash-clone-shallow-deep?path=server.js:1:0
You are using the same variable data inside and outside functions.
ie; data is in the global scope.
static calculate_ai(data){
data.ai = data.areaTotal*data.au
return data
}
even though you are expecting the scope of the variable data inside the method calculate_ai to be limited to that method, it is not the case. data is in global scope and therefore, the value changes inside the method for the variable affects outside as well.
An effective solution is to use a different variable inside the method.
A variable is like an octopus tentacle, and not as a box (as it’s commonly described). In this analogy, the variable's name can be thought of as the name of a tentacle.
A variable (tentacle) holds on to a value in what’s called a binding. A binding is an association of a variable to a value: x = 1.
In JavaScript, if a variable b holds on to variable a, changing the value to which variable a holds onto, will change the value to which variable b holds onto, as b and a are referencing to the same value:
let a = {key: 1}
let b = a
console.log(`a: ${a.key}`) // -> 1
console.log(`b: ${b.key}`) // -> 1
a.key = 2
console.log(`a: ${a.key}`) // -> 2
console.log(`b: ${b.key}`) // -> 2
a = {key: 3} // This will point variable 'a' to a new object, while variable 'b' still points to the original object.
console.log(`a: ${a.key}`) // -> 3
console.log(`b: ${b.key}`) // -> 2
I have a couple of functions in a javascript project that accept an object as an argument and are expected to return a copy of this object with a few changes. I'm trying to make these functions immutable, but the argument can be either an Object or an Array, so I can't just use Object.assign({}, original) or {...original}.
Instead, I've come up with a couple of options:
let doSomething = function doSomething(original) {
let ret = Object.assign(Array.isArray(original) ? [] : {}, original);
//OR
let ret = Array.isArray(original) ? [...original] : {...original};
//OR
let ret = Object.assign(new (original.constructor), original);
//OR
let ret;
if(Array.isArray(original))
ret = original.slice();
else
ret = Object.assign({}, original);
//make changes
return ret;
}
Out of the four, my preference would be for the third method, just because it supports any type of object (not that I plan on using anything other than Objects or Arrays), but it feels "clever" in a bad way.
Out of the four methods, which is best for readability? Or is there another preferred way to copy any type of Object?
Options #1, #2 and #4 are doing completely the same. As for readability my vote is for #2 - shortest and clearest.
Option #3 also recreates constructor/prototype chain that is not you need in this case. It will allow to run check like copiedObj instanceof OriginalObjectClass. But it also may fail once constructor expects some arguments(and does not get them obviously). So in your case it looks rather dangerous approach than helpful.
Also I completely agree with D Lowther it would be better to extract cloning itself from your recursive function.
But I guess that you don't only want to clone some object but also process clone's nested property recursively. And this way you will also require to check if this object or array, right? So instead of cloning array separately and then cloning its members it would be easier to do that in one line with .map:
function cloneRecursively(originalItem) {
let clonedItem = {...originalItem};
clonedItem.children = (clonedItem.children || []).map(cloneRevursively);
return clonedItem;
}
You can use the constructor method instead of new (original.constructor)!
As your param can be an object or an array, you could simply write it like this:
let ret = Object.assign(original.constructor(), original)
Calling it like that, will return an empty object or array.
Be aware that if your param is not a plain JS object, using constructor would either fail or return something unexpected
I'm trying to implement a dictionary much like Python. So, I would like to have a keys() method that returns keys added to the subclass Dict, but not properties such as the Object's method "keys"
EDIT AGAIN
Basically, I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}. It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects. So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.
ie don't return this.prototype.propertyName when own is passedHere's what I have so far:
function Dict(){
this.prototype = {};
var _keys = this.prototype.keys;
this.keys = function(own){
if(typeof own === 'undefined') { return _keys(); }
var ownKeys = [];
for(var key in _keys()){
if(this.hasOwnProperty(key)) {
ownKeys.push(key);
}
}
return ownKeys;
}
}
Will this work as follows? Is there a better or already existent way to do it?
save the overloaded keys() method to a private var
return everything as usual, unless own is something that resolves to true.
if own == true, get the usual keys and filter out those
belonging to the superclass.
On the subject, I'm likely most concerned about saving back the prototype method as a way to get all of the keys and filter out proto keys.
Also, I've read overloading isn't built into Javascript. But, much of what I've found deals with standalone functions such as this Q&A on best practices. I don't need a built in way, but I'll take advantage of whatever's available (Hence, using Object as a Dict).
Any feedback is appreciated!
EDIT
In Python, we get this:
In[2]: d = {}
In[3]: 'has_key' in d.keys()
Out[3]: False
In[7]: 'has_key' in d.__class__.__dict__.keys()
Out[7]: True
In[8]: d.has_key('has_key')
Out[8]: False
In[9]: d['newKey'] = 5
In[10]: d.newKey # ERROR
Python has a dict attribute contained in its class where the functions are accessed via a dot (see In[8]...). So, those standard {} or dict() functions and operators are hidden (not private) while keys/data are added to the user's dict are accessed via []. d['newKey'] = 5 adds a new key or overwrites the old and sets the data to 5.
I don't need all of that to work, though it would be great. keys() returning Python-like keys would be fine for now.
There seem to be multiple issues here.
You seem to want to pass variable arguments to a function:
I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}.
JS function arguments are very flexible.
You can either set up names for every one of them:
function foo(arg1, arg2, map, alphaMap)
and pass values directly. This style is preferred for functions that work on a fixed set of arguments.
Or you can set up an "options" object that collects keys and values:
function foo(options)
and pass {arg1: val1, arg2: val2, map: valMap, alphaMap: valAlphaMap}. This style often occurs on constructor functions that initialize objects with a certain set configuration options.
Or you can set up an empty function signature
function foo()
and work with the arguments collection inside the function. This is found in functions that work with a variable number of uniform arguments (imagine add(1, 2, 3, 4, 6)) or strictly positional arguments instead of named ones.
In any case, passing arguments to a function is optional in JavaScript, even when there is an argument list in the function signature. You are free to pass none, less or more arguments. Of course all these approaches can be combined if it suits you.
It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects.
This is a problem caused by the asynchronous nature of the web. The solution is to use event handlers. These are either callbacks or - as an abstraction over callbacks - promises.
So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.
This can be solved by not adding methods etc to data objects, or at least not directly. Add them to the prototype if your data objects must have behavior.
The direct equivalent to a Python Dict is a plain object in JavaScript.
var dict = {};
The direct equivalent of Python's keys() method is the Object.keys() static method in JavaScript.
var keys = Object.keys(dict);
To iterate the keys you can either use an imperative approach:
var i, key;
for (i = 0; i < keys.length; i++) {
key = keys[i];
doSomething(key, dict[key]);
}
or a functional one
keys.forEach(function (key) {
doSomething(key, dict[key]);
});
The direct equivalent of Python's in is .hasOwnProperty() in JavaScript:
if ( dict.hasOwnProperty('foo') ) ...
or, if it is a pure data object with no prototype chain, you can use in as well.
if ('foo' in dict)
Using in in for loops is not recommendable because it iterates the prototype properties as well. The way to guard against this is by using Object.keys() instead or by combining it with .hasOwnProperty(), as you did.
var key;
for (key in dict) {
if ( dict.hasOwnProperty(key) ) ...
}
Your question indicates that you are missing basic puzzle pieces about JS and try to substitute them with more familiar Python constructs. I would recommend not doing that.
I also suspect that you try to shoehorn Python's class-based inhertiance pattern into JS' prototype-based inheritance pattern. I strongly recommend that you don't do that, either.
A JavaScript WeakMap does not allow you to get the key, or the length or size, by design.
Is it possible to nevertheless loop over entries in some way ?
If not .. how does the Chrome console do this ?
Is it possible to nevertheless loop over entries in some way?
No, as you say, the contents of a WeakMap are not accessible by design, and there is no iterability.
If not … how does the Chrome console do this?
The console uses the debugging API of the JS engine, which allows access to the internals of objects (also to promise states, wrapped primitives, etc.) and many more.
Things are moving and it will soon be possible to create iterable week maps thanks to weak refs.
See the iterable WeakMap example in the tc39 weakrefs proposal.
(note that it is already possible with nodejs v12.?.? using --harmony-weak-refs flag)
Running far afield with a qualifier in your (2015) question, specifically:
Is it possible to nevertheless loop over entries in some way ?
Yes.
In one ridiculous situation, it is possible to emulate and then iterate the keys and values of a WeakMap, and also to make a proper, independent copy of your WeakMap.
If the WeakMap you wish to clone was built in a very specific fashion by a constructor function, you can do it:
// Define a Constructor-Function
// that makes objects
// containing WeakMaps:
function makeWeakMapObject(){
this.wm1 = new WeakMap();
this.o1 = {};
this.o2 = {"orange":"orange"};
this.wm1.set(this.o1, 37);
this.wm1.set(this.o2, 'azerty');
}
// Construct a new object:
let constructedWeakMapObject = new makeWeakMapObject();
// Then set a new key-value pair
// on the WeakMap in your object;
// because, ya know, otherwise you'd
// just reuse the WeakMap constructor
// and wouldn't need to clone :D
constructedWeakMapObject.added = {"ya":"glad"};
constructedWeakMapObject.wm1.set(constructedWeakMapObject.added, 42);
// In preparation to clone your newly constructed object,
// get that newly constructed object's property descriptors:
let props = Object.getOwnPropertyDescriptors(constructedWeakMapObject);
// Have a gander at those props; just for fun:
console.log({"props":props});
// Attempt to clone the constructedWeakMapObject
// using its ownPropertyDescriptors
let weakClone = new cloneWeak(props);
// and then check out what you made:
console.log({"weakClone":weakClone});
// Verify that you've made an independent clone
// (even though this example is shallow)
// by altering the WeakMap in your weakClone:
weakClone.wm.delete(weakClone.o1);
// Make sure your clone was altered:
console.log(weakClone.wm.get(weakClone.o1));
// And then check to see that the
// changes to your clone
// don't appear on your constructed object:
console.log(constructedWeakMapObject);
console.log(constructedWeakMapObject.wm1.get(constructedWeakMapObject.o1));
// A support function to help you use fresh keys in your cloned WeakMap to keep it independent from your original WeakMap
function cloneObject(obj) { // use something more robust, like underscore: _.cloneDeep(obj); actually, you'll likely have to roll your own so you can make clones of functions... anywho
var clone = {};
for(var i in obj) {
if(typeof(obj[i])==="object" && obj[i] !== null)
clone[i] = cloneObject(obj[i]);
else
clone[i] = obj[i];
}
return clone;
}
// Called as a constructor function w/arguments
function cloneWeak(inco){ // a bit wonky, at least in the middle
this.wm = new WeakMap();
let tempMap;
for(key in inco){
// Build keys on 'this' that match the incoming keys
if(Object.prototype.toString.call(inco[key].value) !== "[object WeakMap]"){
this[key] = cloneObject(inco[key].value);
}
// Reference the incoming map from your temp map
// (this makes the following loop possible)
else{tempMap = inco[key].value;}
}
this.fakeForHack = {}; // no idea why this works
this.wm.set(this.fakeForHack, "ok"); // no idea why this works... without it, the WeakMap entry for made.wm1.get(made.added) won't transfer -> ???
for(key in inco){
if(Object.prototype.toString.call(inco[key].value) !== "[object WeakMap]"){
// Set values for 'this' WeakMap:
this.wm.set(this[key], tempMap.get(inco[key].value));
}
}
}
It's kinda ugly, it's brittle, and it only solves a ridiculous edge-case; you're welcome!
I've created a Javscript prototypal object with a range of attributes. And I need to pass some of these attributes to a function. The function processes the attributes and returns some result.
function ObjCt(id,data) {
this.id = id;
this.data = data;
}
So, I'm trying to pass the data of the chart object to a function. Im calling it as:
var obj=new ObjCt(id,data);
process(obj.id,obj.data);
I read from somewhere that passing a value in JS results in a call by value and passing an object results in a call by reference. Here I am trying to call by value, but, seems whatever processing happens in the process() function is reflected in the object obj.
I checked the variable received in the process function using typeof and it comes up as 'object' and not variable. So, what can I do to pass this data as a value?
Edit
I found a rather tiresome workaround. id is primitive and data is a JSON object. So, I tried this in the process() function
JSON.parse(JSON.stringify(data))
Apparently, all references were slashed here. I have a working implementation now, but, Id still love to see if there is an easier way for passing an attribute as a value.
Edit
Solved the problem. As per Paul's answer, tried a normal step by step cloning and another alternative using jquery extend method which goes like this
var object=$.extend(true,{},oldObject);
and passed the newly created object to the process() function.
Please refer this link: What is the most efficient way to deep clone an object in JavaScript?
In JavaScript, primitives (Number, String) are passed ByVal and Objects (including Array, Function) are passed ByRef.
Most of the time this makes no difference, however you can experience problems when using methods which modify an Object without taking into consideration you may want it elsewhere, too.
To get around this, clone your Object before passing it into such a method.
Array has the native Array.prototype.slice to clone, for Objects you need to loop over keys and recurse over the properties.
Custom function to clone, lets you extend it to do more Objects via instanceof testing
function clone(o) {
var o2 = {}, k;
if (typeof o !== 'object')
return o;
if (o instanceof Array)
return o.slice().map(clone);
if (o instanceof Date)
return new Date(o);
for (k in o)
if (Object.prototype.hasOwnProperty.call(o, k))
o2[k] = clone(o[k]);
return o2;
}
Cloning via JSON, only things which can be written in JSON are supported
function clone(o) {
return JSON.parse(JSON.stringify(o));
}
Pretending to clone by using inheritance
This will not protect foo.bar.baz = primitive, but will protect foo.bar = primitive so how good a choice it is for you depends on what the Object looks like or what is being done to it.
function pseudoclone(o) {
return Object.create(o);
}
Don't try to clone functions, it will go horribly wrong. If you need to modify them somehow, wrap them.
Are you attached to that approach only?
var Chart=function(id,data){
this.ObjCt = function () {
this.id = id;
this.data = data;
}
}
then
var obj=new Chart(id,data);
obj.ObjCt();
//process(obj.id,obj.data);
Assuming that id is primitive and data is an object:
function ObjCt(id, data){
this.id = id;
this.data = eval(data.toSource());
}
This will clone the object held in data with simple trick.