Javascript remove object from property - javascript

If you have an object attached to a property like so :
obj = {};
obj.prop = {name:'test'};
Is there a way, similar to using array.splice, to remove the object from that property, and return it so it can be attached to another object?

Sure you can:
var obj = {};
obj.prop = { name: 'test' };
var newObj = { prop: obj.prop} ; // Copy prop to a new object
delete obj.prop; // delete `prop` on the old object.
document.body.textContent = 'newObj: ' + JSON.stringify(newObj);
delete throws an error in strict mode if the property is an own non-configurable property (returns false in non-strict). It returns true in all other cases.
So, while there technically isn't a function like pop or splice that returns the removed property, it's trivial to work around that.

To delete/return a property from an object in one swoop, I think you need your own function for this. Something like:
function removeValue(obj, property) {
var prop = obj[property];
delete obj[property];
return prop;
}

Related

override object accessot javascript [duplicate]

This question already has answers here:
Is there an equivalent of the __noSuchMethod__ feature for properties, or a way to implement it in JS?
(6 answers)
Closed 7 years ago.
I would like to override accessor of a javascript object so that instead of override it should return a fixed value.
eg.
var obj = {};
console.log(obj.someProperty) //will print undefined expected value false
If a property is undefined there is no way to have it return false by default but it will be "falsey".
For example:
var obj = {};
if (!obj.someProperty) {
console.log("expression is falsey");
}
A more explicit way to test truthiness is to use the double bang operator:
var obj = {};
console.log(!!obj.someProperty) // print's undefined, but evaluates to false
But in short, what you are going after will not work because in JavaScript you cannot redefine undefined.
I would do this with the following:
var obj = {};
if (!obj.hasOwnProperty('itdoesnthavethis')) console.log('property is not there')
This will always return a boolean and will not check through the object's prototype chain for the property, just the object itself.
Read more here : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
With ES6 and its Proxy feature you can do something like this:
var obj = {};
obj = new Proxy(obj, {
get: function(target, prop) {
var pv = target[prop];
return pv === undefined ? false : pv;
}
});
that will essentially create proxy wrapper around your object handling property get operations.
With ES5 something like that is impossible to achieve for an arbitrary property.
But if set of properties is known you can design your own object class:
function MyObject() {}
MyObject.prototype.foo = false;
MyObject.prototype.bar = false;
MyObject.prototype.baz = false;
and use it as:
var obj = new MyObject();
console.log(obj.foo); // false
console.log(obj.bar); // false
console.log(obj.foobar); // undefined

Javascript nested objects to JSON: how to filter attributes

I have a hierarchy of JS Objects, like this:
function Obj1(){
this.att1;
this.Obj2Array;
}
function Obj2(){
this.att1;
this.att2;
}
where Obj1 has a reference to an array of Obj2. As you can see Obj1 and Obj2 can have similar attribute names. no guarantee for uniqueness.
I want to get the JSON of Obj1, and I want to exclude some attributes of Obj2.
I know that stringify receives a replacer function or array, And I have tried it but there is the following problem:
When I use a replacer function, how can I differentiate between attributes in Obj1 and Obj2, even if they have the same name? my final goal is to have a behavior like Java toString, where each Object gets to make a decision about its attributes:
Obj1.prototype.stringify = function (key, val){
// if own attribute, return val;
// else it is an Obj2 attribute, return Obj2.prototype.stringify(key, val)
}
Obj2.prototype.stringify = function (key, val){
if (key == "att1"){
return "";
} else if (key == "att2"){
return val;
}
}
I suppose I am missing a better solution.
A good solution is using 'toJSON' function!
Just as Java's printing operation that calls toString, In Javascript, the JSON.stringify function calls the object's 'toJSON' function. A user defined toJSON function changes the behavior and you can pick each object's attributes.
It goes like this:
Obj1.prototype.toJSON = function (){
return {
att1: this.att1,
obj2array: this.Obj2Array
};
}
Obj2.prototype.toJSON = function (){
return {
att2: this.att2
};
}
for using it:
var o1 = new Obj1;
// assign anything you want to o1...
JSON.stringify(o1);
Reading your code i think that you want keep attributes from Obj1 and only get non existent attributes for Obj2. You can do that with assign method in the next way:
var Obj1 = {
attr1: 'foo'
};
var Obj2 = {
attr1: 'foo2',
attr2: 'bar'
};
// now, c has attr1: 'foo' (from Obj1) and attr2: 'bar' (from Obj2)
var c = Object.assign({}, Obj2, Obj1);
// and finally call json stringify with new object
JSON.stringify(c);
With Object.assign you can clone or merge objects: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/assign

Replace object value without replacing reference

How can you update an entire object, say:
var x = {a:1}
function modify(obj) {
obj = {b:2}
}
modify(x)
console.log(x) // {a:1}
But maintain the reference? I want the object to be modified outside the function.
My specific case is using lodash.pick inside my function:
if (whitelist) {
obj = _.pick(obj, whitelist)
}
I can't seem to find a pick function that modifies the object. Is there a way to do this or do I need to start returning copies of the object?
delete everything from the old object, and then add new properties, key-by-key:
function modify(obj, newObj) {
Object.keys(obj).forEach(function(key) {
delete obj[key];
});
Object.keys(newObj).forEach(function(key) {
obj[key] = newObj[key];
});
}
var x = {a:1}
modify(x, {b:42})
document.write(JSON.stringify(x));
If you're wondering whether it's a good idea in general, the answer is no. Construct a new object, return it from the function and assign - this is a much preferred way.
You can achieve this (not exactly what you want) if you wrap your object and change the modify function like this,
var wrapper = {};
wrapper.x = {a:1};
function modify(obj, key) {
obj[key] = {b:2};
}
modify(wrapper, 'x');
console.log(wrapper.x); // {b:2}
/**
* Method to deep update the values of the source object from new object without changing source object reference
*
* #export
* #param {*} sourceObj
* #param {*} newObj
*/
export function updateObjKeepingRef(sourceObj: any, newObj: any): void {
Object.keys(newObj).forEach(key => {
// if value is object and instance is not Date
if (newObj[key] && typeof newObj[key] === 'object' && sourceObj[key] && !(newObj[key] instanceof Date)) {
updateObjKeepingRef(sourceObj[key], newObj[key]);
} else {
// updating properties
sourceObj[key] = newObj[key];
}
});
}
Why does modify not edit the object referred to by obj?
Because inside modify when you write:
obj = {b:2}
Note that obj is a local variable to the function call of modify. A new object {b:2} is created, and the local variable obj now refers to this new object. Recall that the variable x still refers to the {a:1} object.
If x is a global variable AND if there is no local variable inside the function by the name, then you can do:
var x = {a:1};
function modify() {
x = {b:2}
}
modify();
console.log(x) // {b:2}
Why does the above code work?
When you call modify(), it tries to see if it has a local variable x, since it could not find one, it looks up in the scope chain. The next scope to look for this function call is the global scope, and sure enough, there we have a x variable. Hence this global variable x's value is set now.
I was having this issue. After some research, I opted to convert objectTwo to a JSON string, and then replace objectOne with the parsed version. In other words:
var mObjectOne = { ExampleProperty: 10 };
var mObjectTwo = { ExampleProperty: 15 };
// I wanted mObjectOne to hold the same data as mObjectTwo, but keep a separate reference
var mObjectTwoAsJSON = JSON.stringify(mObjectTwo);
mObjectOne = JSON.parse(mObjectTwoAsJSON);
// Now the references are still different, as desired, but the object data has been updated.
Thanks,
obj = JSON.parse(JSON.stringify(newObj))

Are JavaScript objects are one way chaining or two way?

I am trying this example from Douglas Crokford video, and as per my knowledge, changing the new object should not change the old object.
var oldObject = {
firstMethod:function(){
console.log("This is first method");
},
secondMethod:function(){
console.log("This is second method");
}
}
var newObject = Object(oldObject);
newObject.thirdMethod=function(){
console.log("thirdMethod");
}
newObject.firstMethod=function(){
console.log("I am not first method");
}
newObject.firstMethod();
oldObject.firstMethod();
Output:
I am not first method
I am not first method
But I expected,
I am not first method
This is first method
Please let me know where I am wrong.
If you call the Object constructor as a function, it performs type conversion (in this case nothing since the argument is already an object). (If you were to call it as a constructor and pass it an object, as you do there, then it just returns that object).
newObject isn't a new object, it is the same object. Any modifications to newObject are therefore also modifications to oldObject.
Possibly you want:
var newObject = {};
newObject.prototype = oldObject;
Instead of the Object() call.
TL;DR: that's (most probably) a typo in your code: it should have been written like this:
var newObject = Object.create(oldObject);
Now for explanations. This line ...
var newObject = Object(oldObject);
... does not create a new object: instead newObject variable becomes storage of the reference to the same object oldObject refers to. Here's what standard says about it:
15.2.1.1: When the Object function is called with no arguments or with one argument value, the following steps are taken:
If value is null, undefined or not supplied, create and return a new Object object exactly as if the standard built-in Object constructor had been called with the same arguments
Return ToObject(value).
9.9: The abstract operation ToObject converts its argument to a value of
type Object according to Table 14: [ ... ]
Object: The result is the input argument (no conversion).
What you probably wanted to do is use oldObject as a prototype of the new one instead. The most 'direct' way of doing it, when you already have an object, is working with __proto__ property:
var newObject = {
firstMethod: function() { console.log("I am not the firstMethod"); },
thirdMethod: function() { console.log("thirdMethod"); }
};
newObject.__proto__ = oldObject;
This feature is quite ubiquitous these days (apart from IE10-, basically all modern browsers support it). It's not a part of ES5 standard, but it probably will be of ES6.
But I guess Crockford actually meant it this way:
var newObject = Object.create(oldObject);
... as this, quoting the standard yet again, 'creates a new object with a specified prototype'.
Javascript pass object as "reference", so
var newObject = oldObject; // the old Object() just make a type cast, not necessary here
Just make newObject/oldObject reference the same object, and
newObject.firstMethod =
will just overwrite the firstMethod of oldObject too.
So to make newObject a new object, you need to do this:
var newObject = {}; //a new object
for(var k in oldObject)
{
newObject[k]= oldObject[k]; //copy old attrs
}
And then you can overwrite the methods
Yep, when you try to copy an object in javascript it simply passes it as a reference to the original, so any changes to new ones will affect the original. If you are using jQuery simply do this:
var newObject = $.extend({},oldObject);
That should solve your issue. Take a look at this for a more in-depth answer: How do I correctly clone a JavaScript object?
EDIT
Also, from the above thread a non jQuery solution:
Object.prototype.clone = function() {
if(this.cloneNode) return this.cloneNode(true);
var copy = this instanceof Array ? [] : {};
for(var attr in this) {
if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
copy[attr] = this[attr];
else if(this[attr]==this) copy[attr] = copy;
else copy[attr] = this[attr].clone();
}
return copy;
}

Making primitive data types readOnly/nonConfig in JavaScript

Does anyone have any example implementation of making individual object props readOnly/non-configurable? I mean primitive data types. Have tried using ES5 Object API, but hitting a brick wall.
I can't show code, because it's still at that "messy" phase, but basically I'm iterating through an outside object which, itself, holds numeruos objects. Those objects each hold various primitive data types. I have made the outer objects readOnly, non-config, etc, but can't figure out how to do likewise for individual props, the innermost props.
So, if outer.inner.prop === "Hello", I want to make that value readOnly.
Thanks!
UPDATE
I just figured this out, it was all in the for loop I was using to iterate over props. Now I've actually get data descriptors for the props, even the primitive ones. :) Thanks all!
You have to iterate through the inner object, since there is no way to deep-freeze an object using standard ES5 methods.
function deepFreeze(obj) {
Object.keys(obj).forEach(function (key) {
if (typeof obj[key] == 'object')
deepFreeze(obj[key]);
});
Object.freeze(obj);
}
Edit:
Also works for defineProperty if you don't want to freeze:
function deepWriteProtect(obj) {
Object.keys(obj).forEach(function (key) {
if (typeof obj[key] == 'object')
deepWriteProtect(obj[key]);
Object.defineProperty(obj, key, { writable: false });
});
}
I'm not 100% sure I understand your question correctly, but from what I gather you are asking for private variables. If so, that can be easily achieved using closures.
function myClass(){
var mySecretProperty = 10;
this.getMySecretProperty = function(){
return mySecretProperty;
}
this.changeMySecretProperty = function(s){
// whatever logic you need for a setter method
mySecretProperty = s;
}
}
var myObj = new MyClass();
myObj.changeMySecretProperty(120);
myObj.getMySecretProperty(); // will return 120
myObj.mySecretProperty // will return undefined
Would the following (ES5) example help? It creates an empty constructor, with a getter for property a (and no setter, so de facto a is read only):
var Obj = function(){};
Obj.prototype = {
get a() {return 5;}
}
var x = new Obj;
alert(x.a); //=> 5
x.a = 6; //=> TypeError: setting a property that has only a getter
Not using ES5 you can do
var Obj = function(){
var a = 5;
if (!Obj.prototype.getA) {
Obj.prototype.getA = {
toString: function() {
return a;
}
};
}
}
var y = new Obj;
alert(y.getA); //=> 5
But that is not 100% failsafe: Obj.prototype.getA can be overwritten.
Here is a jsfiddle showing how you can use ES5 getter/setter definitions to make a property of an object something that can only be fetched. The code looks like this:
var object = {
get x() {
return 17;
}, set x() {
alert("You cannot set x!");
}
};
Of course the getter could obtain the value of the property ("x") from anywhere, like a closure from a constructor or something. The point is that the setter simply does not change the value, so attempts to change it:
object.x = 100;
will not have any effect.

Categories

Resources