Take the below object:
var value = 'bar';
var obj = { foo: value }
// -> Object { foo="bar" }
Supposing the key was also a variable, one could go:
var key = 'foo', value = 'bar';
var obj = {}
obj[key] = value;
// -> Object { foo="bar" }
Now, I want to do this in one line (shorthand). So I tried:
var obj = {}[key] = value; // or,
var obj = ({})[key] = value; // or,
var obj = new Object()[key] = value;
// -> "bar"
This oddly produces a String instead of an Object.
Is there any way to do this shorthand?
ECMAScript 6 will allow you to do
var obj = {
[key]: value
};
Browser support is not great yet, but transpilers such as 6to5 allow you to use this notation today!
You can, or almost can. If you put the creation of the object, and its assignment to obj in parentheses, you can set a property of the result of that expression:
var obj, key='foo', value = 'bar';
(obj = {})[key] = value;
alert(obj); // [object Object]
alert(obj.foo); // bar
The var keyword cannot be included in that expression within parentheses, so either you will have to declare obj before (like I did), or not declare it at all and accept that it will be in global scope.
Depends on what you call a one-liner, with some code golf you can do
var obj = (function(o) {o[key]=value; return o})({});
it think that's the shortest you'll get it ?
Something like that is coming in ECMAScript 6:
With ECMAScript 6, there is a shorter notation available to achieve
the same:
var a = "foo",
b = 42,
c = {};
// Shorthand property names (ES6)
var o = { a, b, c };
So you could create your object with the following code
var foo = 'bar';
var obj = {foo};
No shorthand in ECMAScript 5 (the current version), but you can make a method
function createObject(key, value /*, key, value, ... */ ) {
var object = {};
for (var i = 0; i < arguments.length; i = i + 2) {
object[arguments[i]] = arguments[i+1];
}
return object;
}
Then you can call it like this
var obj = createObject(key, value, 'anotherKey', 'anotherVal');
Related
I'm trying to create a dictionary object like so
var obj = { varName : varValue };
What I'm expecting is if varName='foo', the obj should be {'foo', 'some value' } however what I see is {varName, 'some value'} the value of variable is not being used but a variable name as a key. How do I make it so that varible value is used as key?
Try like this:
var obj = {};
obj[varName] = varValue;
You can't initialize objects with 'dynamic' keys in old Javascript. var obj = { varName : varValue }; is equivalent to var obj = { "varName" : varValue };. This is how Javascript interprets.
However new ECMAScript supports computed property names, and you can do:
var obj = { [varName]: varValue };
Starting with ECMAScript 2015, which has gotten better browser support in the last year(s), you can use the variable index notation:
const obj = { [varName] : varValue };
This is syntactically the same as
var obj = {};
obj[varName] = varValue;
You can also use expressions or Symbols as property key:
const contact = {
company: companyName,
};
const companiesWithContacts = {
[contact.company.toLowerCase()]: true
};
const myList = {
[Symbol.iterator]: createIteratorForList
};
function createIteratorForList() { ... }
I'm trying to create a var with a couple of empty property's in it using JavaScript. In other languages (for sure in swift, but I'm sure in others too,) this is called a struct.
What I want it to look like is something like this:
myStruct {
value1 : String,
value2 : String
}
The closest I found to that is objects (JavaScript Objects), but with that you would have to add values (to my knowledge).
After, I need to add myStruct to an array. I hope this is clear. What is the most efficient way to achieve this?
Method 1:
The simplest of achieving this is to use new in combination with the Function constructor.
var myStruct = function(prop1,prop2){
this.prop1 = prop1;
this.prop2 = prop2;
}
var myStructObj = new myStruct();
var myStructObj2 = new myStruct("prop1","prop2");
var myArr = [];
myArr.push(myStructObj);
myArr.push(myStructObj2);
console.log(myArr);
An enhancement would be to add default params to the constructor and pass arguments while creation.
var myStruct = function(arg1, arg2){
var prop1 = arg1 || "defaultProp1Value";
var prop2 = arg2 || "defaultProp2Value";
this.prop1 = prop1;
this.prop2 = prop2;
}
var myStructObj1 = new myStruct();
//myStructObj1.prop1 is "defaultProp1Value"
//myStructObj1.prop2 is "defaultProp2Value"
var myStructObj2 = new myStruct("prop1");
//myStructObj2.prop1 is "prop1"
//myStructObj2.prop2 is "defaultProp2Value"
var myArr = [];
myArr.push(myStructObj1);
myArr.push(myStructObj2);
With ES6, you can do this, you can now add default parameters to the constructor.
//This only works in ES6
// Will cause errors on browsers which have not yet added support
// WIll work when used along with a transpiler like Babel
var myStruct = function(arg1 = "defaultProp1", arg2 = "defaultProp2"){
this.prop1 = arg1;
this.prop2 = arg2;
}
var myStructObj1 = new myStruct();
//myStructObj1.prop1 is "defaultProp1Value"
//myStructObj1.prop2 is "defaultProp2Value"
var myStructObj2 = new myStruct("prop1");
//myStructObj2.prop1 is "prop1"
//myStructObj2.prop2 is "defaultProp2Value"
var myArr = [];
myArr.push(myStructObj1);
myArr.push(myStructObj2);
console.log(myArr);
You can read more about it here
Method : 2
Using call method. With this approach you can add props on the fly. Whenever you want to add a couple of props to an object with either null values or default values you can use this approach.
var addPropsFunction = function(a,b){
this.prop1 = a;
this.prop2 = b;
}
var myObj1 = {};
var myObj2 = {};
addPropsFunction.call(myObj1);
addPropsFunction.call(myObj2,"val1","val2");
console.log(myObj1);
console.log(myObj2);
Method : 3
ES6 Classes
class myStruct{
constructor(prop1,prop2){
this.prop1 = prop1;
this.prop2 = prop2;
}
}
var myObj = new myStruct();
console.log(myObj);
Es6 Fiddle - http://www.es6fiddle.net/ifz3rjcc/
In all cases, changing properties is the same.
To change prop1's value, all you have to do is
myStructObj.prop1 = "my val";
null is a value which means "no value". Assigning null to your properties yields exactly what you need.
Well you could do
var myArray = [
{"value1":"Value1Here", "value2":"Value2Here"},
{"value1":"Value1Here", "value2":"Value2Here"},
{"value1":"Value1Here", "value2":"Value2Here"}
];
(these values can be null)
or you could declare your object as above
and do :
myArray.push(yourObject)
I think by now you know how to create a struct in JS.
Now, to initialize properties with empty values:
You have to use either null or undefined based on your requirement.
These links can help you in understanding what and how exactly you have to proceed.
null and undefined
Which one to use?
For security purposes, I have a need for a "mirrored" object. i.e. if I create object A, and shallow-clone a copy of A and call it B, whenever a property of A changes, I hope to have B automatically update itself to reflect the changes, but not the other way around. In other words, one-way property syncing.
My question: is there already a solution out in the wild that I'm not aware of?
Was thinking of implementing a library with observe-js (https://github.com/polymer/observe-js), but thought I should ask around before proceeding. Thanks.
Assuming you don't need to support IE8 and earlier, you can use getters to do that on modern browsers.
function proxy(src) {
var p = {};
Object.keys(src).forEach(function(key) {
Object.defineProperty(p, key, {
get: function() {
return src[key];
}
});
});
return p;
}
var a = {
foo: "Original foo",
bar: "Original bar"
};
var b = proxy(a);
console.log(b.foo); // "Original foo"
a.foo = "Updated foo"; // Note we're writing to a, not b
console.log(b.foo); // "Updated foo"
You can setup the prototype chain for this:
var a = {};
var Syncer = function(){};
Syncer.prototype = a;
var b = new Syncer();
a.foo = 123;
b.foo; // 123
b.bar = 456;
a.bar // undefined
Any property not set on b directly will be looked for on the prototype object, which is a.
You can even wrap this up in a convenience function:
var follow = function(source) {
var Follower = function(){};
Follower.prototype = source;
return new Follower();
}
var a = {};
var b = follow(a);
a.foo = 123;
b.bar = 456;
a.foo; // 123
b.foo; // 123
a.bar; // undefined
b.bar; // 456
I am in the final stages of a game development and i have a bunch of objects like this;
roomBedroom = function () {
this.title = "Bedroom";
this.description = "I'm in a bedroom";
this.noun = "bed";
this.entities = new Array();
}
var bedroom = new roomBedroom();
What I want to do now is place all of my game objects into an array;
var savedGameObjects = {};
savedGameObjects['bedroom'] = bedroom;
var jsonGame = JSON.stringify(savedGameObjects);
The plan is to then save the savedGameObjects array and then recall it when the user loads the game again.
If I replace savedGameObjects['bedroom'] = bedroom; with savedGameObjects['bed'] = 'slappy'; it works but not when I have the object.
I really need to save the objects in their current state. I'd rather not go through each object saving key pieces of information one by one.
This feels like a bit of a hack, but its the best I can come up with right now
Your serialization/deserializtion utility
This is going to attach obj.constructor.name to obj.__prototype before serialization. Upon deserializing, the prototype will be put back in place.
(function(global) {
function serialize(obj) {
obj.__prototype = obj.constructor.name;
return JSON.stringify(obj);
};
function deserialize(json) {
var obj = JSON.parse(json);
obj.__proto__ = global[obj.__prototype].prototype;
return obj;
}
global.serialize = serialize;
global.deserialize = deserialize;
})(window);
A sample "class"
(function(global) {
function Foo() {
this.a = "a";
this.b = "b";
}
Foo.prototype.hello = function() {
console.log("hello");
}
global.Foo = Foo;
})(window);
Let's try it out
var foo = new Foo();
var json = serialize(foo);
console.log(json);
var newFoo = deserialize(json);
console.log('a', newFoo.a); // a
console.log('b', newFoo.b); // b
newFoo.hello(); // hello
Watch out for some gotchas
If you use an expression to define your "class", you will have a nameless constructor
var Foo = function() {};
var foo = new Foo();
foo.constructor.name; // ""
As opposed to a named function
function Foo() {}
var foo = new Foo();
foo.constructor.name; // Foo
In order for serialize and deserialize to work, you will need to use named functions
Another gotcha
The deserialize method expects your "classes" to exist on the in the same namespace (window in this case). You could encapsulate your game object classes in another way, just make sure that you reconfigure the deserialize method so that it can find the prototypes as needed.
Making this better
Instead of attaching serialize to the global window, you could have serialize live on (e.g.) the GameObject.prototype then your individual classes could inherit from GameObject. Serializing an object would then be as simple as
var json = foo.serialize();
// {"a":"a","b":"b","__prototype":"Foo"}
You could then define deserialize as GameObject.deserialize and restoring foo would be
var foo = GameObject.deserialize(json);
An alternative solution
Instead of implementing a custom serializer and deserializer, you could make very clever use of the Factory Method Pattern.
This might be a little verbose, but it does give you individual control over how a game object should be deserialized/restored.
var savedData = // your normal JSON here
var player = Player.create(savedData.player);
var items = [];
for (var i=0, i<savedData.items.length; i++) {
items.push(Item.create(savedData.items[i]));
}
var map = Map.create(savedData.map);
This was a pretty interesting problem and I'm sure you're not the first to encounter it. I'm really curious to see what other people come up with.
If I run the following code in a browser there is no problem getting the JSON string of the bedroom object, not sure what the problem is.
Note that JSON is data and bedroom is an object, bedroom may have behaviour like turnOffLight() that JSON doesn't have.
roomBedroom = function () {
this.title = "Bedroom";
this.description = "I'm in a bedroom";
this.noun = "bed";
this.entities = new Array();
}
var bedroom = new roomBedroom();
var savedGameObjects = {};
savedGameObjects['bedroom'] = bedroom;
//logs {"bedroom":{"title":"Bedroom","description":
// "I'm in abedroom","noun":"bed","entities":[]}}
console.log(JSON.stringify(savedGameObjects));
So if you want to re create object instances from JSON data then you can change your constructor:
roomBedroom = function (args) {
//following fails fast and loud, you could silently
//fail by setting args to {}
if(typeof args!=="object")
throw new Error("Have to create roomBedroom by passing an object");
//or do args={} to silently fail
this.title = args.title||"Bedroom";
this.description = args.description||"I'm in a bedroom";
this.noun = args.noun||"bed";
//if entities are objects with behavior
// you have to re create them here passing the JSON data
// as I've done with roomBedroom
this.entities = args.entities||new Array();
}
var jsonString='{"bedroom":{"title":"Bedroom",'+
'"description":"I\'m in a bedroom",'+
'"noun":"bed","entities":[]}}';
var bedroom = new roomBedroom({});
bedroom.entities.push({hi:"there"});
bedroom.title="Master Bedroom";
//serialize bedroom to a json string
var jsonString = JSON.stringify(bedroom);
//create a roomBedroom instance named br2 using
// the serialized string
var br2=new roomBedroom(JSON.parse(jsonString));
//compare if they are the same
console.log(JSON.stringify(bedroom)===JSON.stringify(br2));//true
I have an approach that might work for you. You can see it in action on JSFiddle.
The main point is to use the reviver parameter to JSON.parse to reconstruct your object when it's parsed.
I do this with a general-purpose reviver that can be configured for multiple different types, although here the only one used is the RoomBedroom constructor. This implementation assumes that you have simple copy constructors that create new objects using a reference to an existing one. (For other, more sophisticated possibilities, see an answer to another question I gave in February.) To make it easy to have a copy constructor, I have one more function that accepts a very simple constructor function and a set of default values and builds a copy constructor function for you.
var MultiReviver = function(types) {
return function(key, value) {
var type;
for (var i = 0; i < types.length; i++) {
type = types[i];
if (type.test(value)) {
return new type.constructor(value);
}
}
return value;
};
};
var makeCloningConstructor = (function() {
var clone = function(obj) {return JSON.parse(JSON.stringify(obj));};
var F = function() {};
return function(Constructor, defaults) {
var fn = function(obj) {
Constructor.call(this);
var self = this;
var config = obj || {};
Object.keys(defaults).forEach(function(key) {
self[key] = clone(defaults[key]);
});
Object.keys(config).forEach(function(key) {
self[key] = clone(config[key]);
});
};
F.prototype = Constructor.prototype;
fn.prototype = new F();
fn.constructor = Constructor;
return fn;
};
})();
// Note: capitalize constructor functions
var RoomBedroom = makeCloningConstructor(function RoomBedroom() {}, {
title: "Bedroom",
description: "I'm in a bedroom",
noun: "bed",
entities: [] // Note: use `[]` instead of `new Array()`.
});
RoomBedroom.prototype.toggleLight = function() {
this.lightOn = !this.lightOn;
};
RoomBedroom.prototype.checkLights = function() {
return "light is " + (this.lightOn ? "on" : "off");
};
var bedroom = new RoomBedroom();
bedroom.windowCount = 3; // add new property
bedroom.noun = "king-sized bed"; // adjust property
bedroom.toggleLight(); // create new propery, use prototype function
console.log(bedroom.checkLights());
var savedGameObjects = {};
savedGameObjects['bedroom'] = bedroom;
var jsonGame = JSON.stringify(savedGameObjects);
var reviver = new MultiReviver([{
constructor: RoomBedroom,
test: function(obj) {
var toString = Object.prototype.toString, str = "[object String]",
arr = "[object Array]";
return toString.call(obj.title) == str &&
toString.call(obj.description) == str &&
toString.call(obj.noun) == str &&
toString.call(obj.entities) == arr;
}
}]);
var retrievedGameObjects = JSON.parse(jsonGame, reviver);
// data comes back intact
console.log(JSON.stringify(retrievedGameObjects, null, 4));
// constructor is as expected
console.log("Constructor: " + retrievedGameObjects.bedroom.constructor.name);
// prototype functions work
console.log(retrievedGameObjects.bedroom.checkLights());
I don't know if it's precisely what you were looking for, but I think it's at least an interesting approach.
the faster route
It is better — from an optimisation point of view — to do as Adeneo states, which is power each of your Game Objects by an exportable simple object i.e:
roomBedroom = function(){
this.data = {};
this.data.title = 'Bedroom'
/// and so on...
}
These can then be easily stored and re-imported just by JSON.Stringifying and overwriting the data property. For example, you could set-up the system that Maček mentions (+1) which is to give each of your game objects serialize and deserialize functions:
roomBedroom.prototype.serialize = function(){
return JSON.stringify( this.data );
};
roomBedroom.prototype.deserialize = function( jstr ){
this.data = JSON.parse(jstr);
};
the quicker way
However, you can make a simple addition to what you already have using the following:
First enhance your Game Objects with an objectName property. This is because constructor.name and function.name are unreliable and do strange things the further back in time you go, far better to use a string you have set in stone.
var roomBedroom = function ( title ) {
this.objectName = "roomBedroom";
this.title = title;
this.description = "I'm in a bedroom";
this.noun = "bed";
this.entities = new Array();
};
Then the additional code to help with storage:
var storage = {};
/// add your supported constructors to this list, there are more programmatic
/// ways to get at the constructor but it's better to be explicit.
storage.constructors = {
'roomBedroom' : roomBedroom
};
/// take an instance and convert to simple object
storage.to = function( obj ){
if ( obj.toStorage ) {
return obj.toStorage();
}
else {
var keep = {};
for ( var i in obj ) {
if ( obj.hasOwnProperty(i) && !obj[i].call ) {
keep[i] = obj[i];
}
}
return keep;
}
}
/// take simple object and convert to an instance of constructor
storage.from = function( obj ){
var n = obj && obj.objectName, c = storage.constructors[n];
if ( n && c ) {
if ( c.fromStorage ) {
return c.fromStorage( obj );
}
else {
var inst = new c();
for ( var i in obj ) {
if ( obj.hasOwnProperty(i) ) {
inst[i] = obj[i];
}
}
return inst;
}
}
else {
throw new Error('`' + n + '` undefined as storage constructor');
}
}
Once you have that you can use it like so:
var savedGameObjects = {};
savedGameObjects['bedroom'] = storage.to(new roomBedroom("bedroom"));
savedGameObjects['bedroom2'] = storage.to(new roomBedroom("bedroom2"));
var jsonGame = JSON.stringify(savedGameObjects);
console.log(jsonGame);
savedGameObjects = JSON.parse(jsonGame);
for( var i in savedGameObjects ) {
savedGameObjects[i] = storage.from(savedGameObjects[i]);
console.log(savedGameObjects[i]);
}
extras
You can also be specific about the way objects get stored/unstored by supplying toStorage and fromStorage methods on your constructed instances and constructors respectively. For example, you could use the following if you only wanted to store titles of roomBedrooms. Obviously this is an unrealistic use-case, you'd more often use this to avoid storing cached or computed sub-objects and properties.
roomBedroom.prototype.toStorage = function( obj ){
var ret = {};
ret.title = obj.title;
return ret;
};
roomBedroom.fromStorage = function( obj ){
var inst = new roomBedroom();
inst.title = obj.title;
return inst;
};
The above also means you can take advantage of improving your Game Object construction by providing parameters, rather than iterating over properties which can be slow and error-prone.
roomBedroom.fromStorage = function( obj ){
return new roomBedroom( obj.title );
};
Or even:
roomBedroom.fromStorage = function( obj ){
return new roomBedroom( obj ); // <-- the constructor processes the import.
};
fiddle
http://jsfiddle.net/XTUdp/
disclaimer
The above code relies on the existence of hasOwnProperty which is not present cross-browser yet, a polyfill should be used until it is... or, if you aren't doing anything complicated with prototype inheritance you don't need to worry and can remove it from the code.
you can declare a big variable like
var world = {};
and each small variable declare as
var bedroom = world.bed = (world.bed || new roomBedroom());
remember never change bedroom to another object, i think this will work fine, but looks too long winded
When passing objects as parameters, JavaScript passes them by reference and makes it hard to create local copies of the objects.
var o = {};
(function(x){
var obj = x;
obj.foo = 'foo';
obj.bar = 'bar';
})(o)
o will have .foo and .bar.
It's possible to get around this by cloning; simple example:
var o = {};
function Clone(x) {
for(p in x)
this[p] = (typeof(x[p]) == 'object')? new Clone(x[p]) : x[p];
}
(function(x){
var obj = new Clone(x);
obj.foo = 'foo';
obj.bar = 'bar';
})(o)
o will not have .foo or .bar.
Question
Is there a better way to pass objects by value, other than creating a local copy/clone?
Not really.
Depending on what you actually need, one possibility may be to set o as the prototype of a new object.
var o = {};
(function(x){
var obj = Object.create( x );
obj.foo = 'foo';
obj.bar = 'bar';
})(o);
alert( o.foo ); // undefined
So any properties you add to obj will be not be added to o. Any properties added to obj with the same property name as a property in o will shadow the o property.
Of course, any properties added to o will be available from obj if they're not shadowed, and all objects that have o in the prototype chain will see the same updates to o.
Also, if obj has a property that references another object, like an Array, you'll need to be sure to shadow that object before adding members to the object, otherwise, those members will be added to obj, and will be shared among all objects that have obj in the prototype chain.
var o = {
baz: []
};
(function(x){
var obj = Object.create( x );
obj.baz.push( 'new value' );
})(o);
alert( o.baz[0] ); // 'new_value'
Here you can see that because you didn't shadow the Array at baz on o with a baz property on obj, the o.baz Array gets modified.
So instead, you'd need to shadow it first:
var o = {
baz: []
};
(function(x){
var obj = Object.create( x );
obj.baz = [];
obj.baz.push( 'new value' );
})(o);
alert( o.baz[0] ); // undefined
Check out this answer https://stackoverflow.com/a/5344074/746491 .
In short, JSON.parse(JSON.stringify(obj)) is a fast way to copy your objects, if your objects can be serialized to json.
Here is clone function that will perform deep copy of the object:
function clone(obj){
if(obj == null || typeof(obj) != 'object')
return obj;
var temp = new obj.constructor();
for(var key in obj)
temp[key] = clone(obj[key]);
return temp;
}
Now you can you use like this:
(function(x){
var obj = clone(x);
obj.foo = 'foo';
obj.bar = 'bar';
})(o)
Use Object.assign()
Example:
var a = {some: object};
var b = new Object;
Object.assign(b, a);
// b now equals a, but not by association.
A cleaner example that does the same thing:
var a = {some: object};
var b = Object.assign({}, a);
// Once again, b now equals a.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Use this
x = Object.create(x1);
x and x1 will be two different object,change in x will not change x1
You're a little confused about how objects work in JavaScript. The object's reference is the value of the variable. There is no unserialized value. When you create an object, its structure is stored in memory and the variable it was assigned to holds a reference to that structure.
Even if what you're asking was provided in some sort of easy, native language construct it would still technically be cloning.
JavaScript is really just pass-by-value... it's just that the value passed might be a reference to something.
ES6
Using the spread operator like obj2 = { ...obj1 }
Will have same values but different references
ES5
Use Object.assign obj2 = Object.assign({}, obj1)
Javascript always passes by value. In this case it's passing a copy of the reference o into the anonymous function. The code is using a copy of the reference but it's mutating the single object. There is no way to make javascript pass by anything other than value.
In this case what you want is to pass a copy of the underlying object. Cloning the object is the only recourse. Your clone method needs a bit of an update though
function ShallowCopy(o) {
var copy = Object.create(o);
for (prop in o) {
if (o.hasOwnProperty(prop)) {
copy[prop] = o[prop];
}
}
return copy;
}
As a consideration to jQuery users, there is also a way to do this in a simple way using the framework. Just another way jQuery makes our lives a little easier.
var oShallowCopy = jQuery.extend({}, o);
var oDeepCopy = jQuery.extend(true, {}, o);
references :
http://api.jquery.com/jquery.extend/
https://stackoverflow.com/a/122704/1257652
and to dig into the source.. http://james.padolsey.com/jquery/#v=1.8.3&fn=jQuery.extend
Actually, Javascript is always pass by value. But because object references are values, objects will behave like they are passed by reference.
So in order to walk around this, stringify the object and parse it back, both using JSON. See example of code below:
var person = { Name: 'John', Age: '21', Gender: 'Male' };
var holder = JSON.stringify(person);
// value of holder is "{"Name":"John","Age":"21","Gender":"Male"}"
// note that holder is a new string object
var person_copy = JSON.parse(holder);
// value of person_copy is { Name: 'John', Age: '21', Gender: 'Male' };
// person and person_copy now have the same properties and data
// but are referencing two different objects
I needed to copy an object by value (not reference) and I found this page helpful:
What is the most efficient way to deep clone an object in JavaScript?. In particular, cloning an object with the following code by John Resig:
//Shallow copy
var newObject = jQuery.extend({}, oldObject);
// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);
With the ES6 syntax:
let obj = Object.assign({}, o);
When you boil down to it, it's just a fancy overly-complicated proxy, but maybe Catch-All Proxies could do it?
var o = {
a: 'a',
b: 'b',
func: function() { return 'func'; }
};
var proxy = Proxy.create(handlerMaker(o), o);
(function(x){
var obj = x;
console.log(x.a);
console.log(x.b);
obj.foo = 'foo';
obj.bar = 'bar';
})(proxy);
console.log(o.foo);
function handlerMaker(obj) {
return {
getOwnPropertyDescriptor: function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
// a trapping proxy's properties must always be configurable
if (desc !== undefined) { desc.configurable = true; }
return desc;
},
getPropertyDescriptor: function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name); // not in ES5
// a trapping proxy's properties must always be configurable
if (desc !== undefined) { desc.configurable = true; }
return desc;
},
getOwnPropertyNames: function() {
return Object.getOwnPropertyNames(obj);
},
getPropertyNames: function() {
return Object.getPropertyNames(obj); // not in ES5
},
defineProperty: function(name, desc) {
},
delete: function(name) { return delete obj[name]; },
fix: function() {}
};
}
If you are using lodash or npm, use lodash's merge function to deep copy all of the object's properties to a new empty object like so:
var objectCopy = lodash.merge({}, originalObject);
https://lodash.com/docs#merge
https://www.npmjs.com/package/lodash.merge