Create an object based on 2 others [duplicate] - javascript

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How can I merge properties of two JavaScript objects dynamically?
I have two objects a and b defined like this:
a = {
a: 1,
af: function() { console.log(this.a) },
};
b = {
b: 2,
bf: function() { console.log(this.b) },
};
What I want now is to create another object which will get the properties of a and b, like this:
c = {
a: 1,
af: function() { console.log(this.a) },
b: 2,
bf: function() { console.log(this.b) },
}
Note that a and b need to stay the same.
Any idea of how to do this ?

You could do a for in loop for both a and b, and copy all hasOwn properties to a new object.
var c = {};
for (var p in a)
if(a.hasOwnProperty(p))
c[p] = a[p];
for (var p in b)
if(b.hasOwnProperty(p))
c[p] = b[p];
DEMO
Or, if you happen to be using jQuery, you could do:
var c = $.extend({}, a, b);

var desc = Object.getOwnPropertyDescriptor,
props = Object.getOwnPropertyNames,
define = Object.defineProperty;
function extend( target ) {
return {
with: function( source ) {
props( source ).forEach(function( key ) {
define( target, key, desc( source, key ) );
});
}
};
}
So now we can go like
var c = Object.create( null );
extend( c ).with( a );
extend( c ).with( b );
Disclaimer: the provided codes assume we are in a ES5 or ES5 shimed environment !

var i, c={};
for (i in a) { if (a.hasOwnProperty(i)) { c[i] = a[i]; } }
for (i in b) { if (b.hasOwnProperty(i)) { c[i] = b[i]; } }
You can abstract this functionality into your own "extend" function similar to the one provided by jQuery:
function extend() {
var i, j, x, o=(arguments[0] || {});
for (i=1; i<arguments.length; i++) {
x = arguments[i];
for (j in x) { if (x.hasOwnProperty(j)) { o[j] = x[j]; } }
}
return o;
}
var c = extend({}, a, b);

Related

Merge 2 array present in object of available keys be removing specific property of object

I have 2 objects a and b which both contains arrays.
I want to Merge the arrays present in each object and form a new object including the arrays and text nodes.
my code :-
var a = {
name1:[1,2],
name2:[3],
name3:'alisha',
name4:'japan'
};
var b = {
name1:[4],
name2:[5,6],
name3:'hello alisha!!'
};
newobject = function (obj1, obj2) {
var obj3 = {};
for (var attrname in obj1) {
obj3[attrname] = obj1[attrname];
}
for (var attrname in obj2) {
obj3[attrname] = obj2[attrname];
}
return obj3;
};
console.log(newobject(a,b))
What I am trying to do :-
I have 2 object a & b which may contain different data as well as similar data. I want to mix the data from the arrays if both objects have the same property, If the property of object is a string i want to update it with **b ** objects same property.
Output may not be accurate but It gives 100% hints to solve this problem
Output I am trying to get:-
{
name1:[1,2,4],
name2:[3,5,6],
name3:'hello alisha!',
name4:'japan'
}
Please don't use jquery
If it's literally the example above that you'd like to merge, then the following will do that for you.
I don't know if it matters in your case, but you may also want to consider handling instances where a.name1 is a string and b.name1 is an array, etc.
var a = {
name1: [1, 2],
name2: [3],
name3: 'alisha',
name4: 'japan'
};
var b = {
name1: [4],
name2: [5, 6],
name3: 'hello alisha!!'
};
function merge(a, b) {
var c = {};
for (var key in a) {
c[key] = a[key];
}
for (var key in b) {
c[key] = (Array.isArray(a[key])) ? a[key].concat(b[key]) : b[key];
}
return c;
}
console.log(merge(a, b));
You may easily extend to check for other types as well, like object etc.
var a = {
name1:[1,2],
name2:[3],
name3:'alisha',
name4:'japan'
};
var b = {
name1:[4],
name2:[5,6],
name3:'hello alisha!!',
name5:'new name'
};
function merge(a, b) {
var c = Object.keys(a).reduce(function(acc, key) {
if(!(key in b)) {
acc[key] = a[key]
} else if(Array.isArray(a[key]) && Array.isArray(b[key])) {
acc[key] = a[key].concat(b[key])
} else {
acc[key] = b[key]
}
return acc
}, {})
c = Object.keys(b).reduce(function(acc, key) {
if(!(key in acc)) {
acc[key] = b[key]
}
return acc
}, c)
return c
}
var d = merge(a, b)
var a = {
name1: [1, 2],
name2: [3],
name3: 'alisha',
name4: 'japan'
};
var b = {
name1: [4],
name2: [5, 6],
name3: 'hello alisha!!'
};
function mergeObjects(a, b) {
for (var key in b) {
a[key] = (Array.isArray(a[key])) ? a[key].concat(b[key]) : b[key];
}
return a;
}
console.log(mergeObjects(a, b));

How to pass an extra parameter despite having default parameters in Javascript?

Consider the example
var example = function(a = 10, b = 15, c) {
return c;
}
So, I want to call the example function with just the value of c. Something like,
example(20); // should return 20, without disturbing the values of a and b
How would I do this in JavaScript?
What you want is can be achieved with destructring assignment but it needs some mods. As i can see you are using es2015/es6 code for setting the default values. You might consider this:
var example = function([a = 10, b = 15, c]) {
console.log(a,b, c);
//return c;
}
example([,,20]);
You should consider using predefined variables in the end of function declaration:
var example = function(a, b = 10, c = 15 ) {
return a;
}
So result would be
example(20); // ->> 20
You could pass null as arguments for a and b when you call example.
var example = function(a = 10, b = 15, c) {
return c;
}
console.log(example(null, null, 20))
Or you could just use object as parameter.
var example = function(obj) {
obj.a = obj.a || 10;
obj.b = obj.b || 15;
return obj.c;
}
console.log(example({c: 20}))
You may have to use object instead :
var example = function(passed_options) {
$.extend( default_options, passed_options );
return c;
}
Hope this helps.
Sample snippet :
var example = function( passed_options ) {
$.extend( {a: 10, b: 15}, passed_options );
return passed_options.c;
}
console.log( example({c: 20}) );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can use a parameter object to simulate named parameters:
var example = function(params) {
const a = params.a || 10;
const b = params.b || 15;
const c = params.c || 20;
}
and invoke:
example({c:42});

jQuery extend multiple objects with the same function

So I'm using $.extend to combine multiple components (objects). Some of these components have a function with the same key. I want the final extended object to have that same key, but have it point to a function which calls all of the merged components' versions of the functions one after the other.
So it'd look something like this:
var a = { foo: function() { console.log("a"); } };
var b = { foo: function() { console.log("b"); } };
var c = {}; // Doesn't have foo
var d = $.extend({}, a, b, c);
var e = $.extend({}, a, c);
var f = $.extend({}, c);
d.foo(); // Should call function() { console.log("a"); console.log("b"); }
e.foo(); // Should call function() { console.log("a"); }
f.foo(); // Should call function() {}
Is there a pragmatic way of doing this? I only want to do this for a specific set of keys, so I would only want to merge those specific keys' functions together and let the ordering in extend overwrite anything else.
Hopefully that makes sense :S
Note
f.foo(); // Should call function() {}
object c does not appear to have property foo . callling f.foo() returns TypeError: undefined is not a function . Not certain if requirement to add foo function to extended f object , or return object c (empty object) from anonymous function ? At piece below , foo function not added to extended f object.
jquery $.Callbacks() utilized to add functions having foo property at $.each()
Try
var a = { foo: function() { console.log("a"); } };
var b = { foo: function() { console.log("b"); } };
var c = {}; // Doesn't have foo
//d.foo();
// Should call function() { console.log("a"); console.log("b"); }
//e.foo();
// Should call function() { console.log("a"); }
//f.foo();
// Should call function() {}
var callbacks = $.Callbacks();
var arr = [], d, e, f;
$.each([a,b,c], function(k, v, j) {
var j = [a,b,c];
// filter objects having `foo` property
if (v.hasOwnProperty("foo")) {
arr.push([v, v.foo]);
if (arr.length > 1) {
callbacks.add(arr[0][1], arr[1][1]);
// `add` `foo` properties to `callbacks`
// `fire` both `callbacks` when `object.foo` called
j[k -1].foo = callbacks.fire;
d = $.extend({}, j[k - 1])
} else {
// `else` extend original data (`fn`, `object`)
// contained within object
e = $.extend({}, j[k + 1]);
f = $.extend({}, j[++k + 1]);
}
}
});
d.foo(); // `a` , `b`
e.foo(); // `b`
console.log(f); // `Object {}`
f.foo() // `TypeError: undefined is not a function`
jsfiddle http://jsfiddle.net/guest271314/3k35buc1/
See jQuery.Callbacks()
Here's what I ended up with based off of guest271314's answer. toMix is the array of components to be mixed into the object. I actually didn't need the dummy functions I thought I might, and I ended up using an array of functions instead of the $.Callbacks() so that I could control the order in which the functions are called. I also needed to use the call() function so that I could call the functions from the correct this object.
this.functionMerge = function(toMix) {
var callbacks = {};
var functions = {};
var obj = {};
var keys = [
'componentWillMount',
'componentDidMount',
'componentWillUpdate',
'componentDidUpdate',
'componentWillUnmount'
]
$.each(keys, function(key, value) {
callbacks[value] = [];
});
for (i = 0; i < toMix.length; ++i) {
$.each(keys, function(key, value) {
if (toMix[i].hasOwnProperty(value) && typeof toMix[i][value] == 'function') {
callbacks[value].push(toMix[i][value]);
}
});
$.extend(true, obj, toMix[i]);
}
$.each(keys, function(key, value) {
functions[value] = function() {
var that = this;
$.each(callbacks[value], function(key, value) {
value.call(that);
});
};
});
return $.extend(true, obj, functions);
}

Why does google main page use (0, obj.func)(args) syntax?

Sometimes I stared at js provided with google.com main page and found that they tended to use (0, obj.func)(args) syntax. Here are excerpts from the script:
var _ = _ || {};
(function (_) {
var window = this;
try {
_.mb = function (a) {
return (0, window.decodeURIComponent)(a.replace(/\+/g, " "))
};
_.zg = function (a, b) {
for (var c = a.length ? a.split("&") : [], d = 0; d < c.length; d++) {
var e = c[d];
if ((0, _.Ag)(e) == b) return (c = /=(.*)$/.exec(e)) ? (0, _.mb)(c[1]) : null
}
return null
};
_.Ag = function (a) {
return (a = /^(.+?)(?:=|$)/.exec(a)) ? (0, _.mb)(a[1]) : null
};
var Cg = function (a, b) {
var c = a.indexOf("?");
return 0 > c ? null : (0, _.zg)(a.substring(c + 1), b)
};
// Note var Cg called with no 0
var oca = function (a) {
this.A = Cg(a, "mods");
this.B = Cg(a, "ver")
};
} catch (e) {}
})(_);
Why prepending 0?
This makes an indirect call.
This ensures the context, in the called function, is the global one. This might be useful in an internal scope.
Example :
var a = {
b: function(){
console.log(this);
},
c1: function(){
this.b();
},
c2: function(){
(0, this.b)();
},
c3: function(){
(this.b)();
}
}
a.c1(); // logs a
a.c2(); // logs window
a.c3(); // logs a

Clone Object without reference javascript [duplicate]

This question already has answers here:
What is the most efficient way to deep clone an object in JavaScript?
(67 answers)
Closed 2 years ago.
I have a big object with much data. And i want to clone this in other variable. When i set some param of the instance B has the same result in the original object:
var obj = {a: 25, b: 50, c: 75};
var A = obj;
var B = obj;
A.a = 30;
B.a = 40;
alert(obj.a + " " + A.a + " " + B.a); // 40 40 40
My output should be 25 30 40.
Any ideas?
EDIT
Thanks Everyone. I change the code of dystroy and this is my result:
Object.prototype.clone = Array.prototype.clone = function()
{
if (Object.prototype.toString.call(this) === '[object Array]')
{
var clone = [];
for (var i=0; i<this.length; i++)
clone[i] = this[i].clone();
return clone;
}
else if (typeof(this)=="object")
{
var clone = {};
for (var prop in this)
if (this.hasOwnProperty(prop))
clone[prop] = this[prop].clone();
return clone;
}
else
return this;
}
var obj = {a: 25, b: 50, c: 75};
var A = obj.clone();
var B = obj.clone();
A.a = 30;
B.a = 40;
alert(obj.a + " " + A.a + " " + B.a);
var arr = [25, 50, 75];
var C = arr.clone();
var D = arr.clone();
C[0] = 30;
D[0] = 40;
alert(arr[0] + " " + C[0] + " " + D[0]);
If you use an = statement to assign a value to a var with an object on the right side, javascript will not copy but reference the object.
Spoiler : using JSON.parse(JSON.stringify(obj)) may work but is costly, and might throw a TypeError as in
const a = {};
const b = { a };
a.b = b;
const clone = JSON.parse(JSON.stringify(a));
/* Throws
Uncaught TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'b' -> object with constructor 'Object'
--- property 'a' closes the circle
at JSON.stringify (<anonymous>)
at <anonymous>:4:6
*/
As of es2015, if you want a shallow copy (clone the object, but keeping deep refences in the inner structure) you can use destructuring :
const obj = { foo: { bar: "baz" } };
const shallowClone = { ...obj };
shallowClone is a new object, but shallowClone.foo holds a reference to the same object as obj.foo.
You can use lodash's clone method, which does the same, if you don't have access to the spread operator.
var obj = {a: 25, b: 50, c: 75};
var A = _.clone(obj);
Or lodash's cloneDeep method if your object has multiple object levels
var obj = {a: 25, b: {a: 1, b: 2}, c: 75};
var A = _.cloneDeep(obj);
Or lodash's merge method if you mean to extend the source object
var obj = {a: 25, b: {a: 1, b: 2}, c: 75};
var A = _.merge({}, obj, {newkey: "newvalue"});
Or you can use jQuerys extend method:
var obj = {a: 25, b: 50, c: 75};
var A = $.extend(true,{},obj);
Here is jQuery 1.11 extend method's source code :
jQuery.extend = jQuery.fn.extend = function() {
var src, copyIsArray, copy, name, options, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
var item ={ 'a': 1, 'b': 2}
Object.assign({}, item);
While this isn't cloning, one simple way to get your result is to use the original object as the prototype of a new one.
You can do this using Object.create:
var obj = {a: 25, b: 50, c: 75};
var A = Object.create(obj);
var B = Object.create(obj);
A.a = 30;
B.a = 40;
alert(obj.a + " " + A.a + " " + B.a); // 25 30 40
This creates a new object in A and B that inherits from obj. This means that you can add properties without affecting the original.
To support legacy implementations, you can create a (partial) shim that will work for this simple task.
if (!Object.create)
Object.create = function(proto) {
function F(){}
F.prototype = proto;
return new F;
}
It doesn't emulate all the functionality of Object.create, but it'll fit your needs here.
You could define a clone function.
I use this one :
function goclone(source) {
if (Object.prototype.toString.call(source) === '[object Array]') {
var clone = [];
for (var i=0; i<source.length; i++) {
clone[i] = goclone(source[i]);
}
return clone;
} else if (typeof(source)=="object") {
var clone = {};
for (var prop in source) {
if (source.hasOwnProperty(prop)) {
clone[prop] = goclone(source[prop]);
}
}
return clone;
} else {
return source;
}
}
var B = goclone(A);
It doesn't copy the prototype, functions, and so on. But you should adapt it (and maybe simplify it) for you own need.
A and B reference the same object, so A.a and B.a reference the same property of the same object.
Edit
Here's a "copy" function that may do the job, it can do both shallow and deep clones. Note the caveats. It copies all enumerable properties of an object (not inherited properties), including those with falsey values (I don't understand why other approaches ignore them), it also doesn't copy non–existent properties of sparse arrays.
There is no general copy or clone function because there are many different ideas on what a copy or clone should do in every case. Most rule out host objects, or anything other than Objects or Arrays. This one also copies primitives. What should happen with functions?
So have a look at the following, it's a slightly different approach to others.
/* Only works for native objects, host objects are not
** included. Copies Objects, Arrays, Functions and primitives.
** Any other type of object (Number, String, etc.) will likely give
** unexpected results, e.g. copy(new Number(5)) ==> 0 since the value
** is stored in a non-enumerable property.
**
** Expects that objects have a properly set *constructor* property.
*/
function copy(source, deep) {
var o, prop, type;
if (typeof source != 'object' || source === null) {
// What do to with functions, throw an error?
o = source;
return o;
}
o = new source.constructor();
for (prop in source) {
if (source.hasOwnProperty(prop)) {
type = typeof source[prop];
if (deep && type == 'object' && source[prop] !== null) {
o[prop] = copy(source[prop]);
} else {
o[prop] = source[prop];
}
}
}
return o;
}

Categories

Resources