JS assignment order of properties in objects - javascript

Just had a quick question about why a certain order of assignment works and another doesn't.
I wanted to create a simple "inherit" / "copy" function (just for testing it) that copies properties from one object to another:
var cat = { tail:"yes", hairy:"yes, hairy" };
var dog = { sick:"extremely ill"};
function inherit(obj1, obj2) {
for (var p in obj1)
{
obj2[p] = obj1[p]; // this works, but "obj1[p] = obj2[p];" doesn't. Why??
}
}
inherit(cat, dog);
console.log(dog.tail);

You are looping over all the properties of obj1, so all those properties exist on obj1.
If you try to copy from obj2 then you are trying to copy properties that don't exist (on that object), so you cause an error.

You're reading the properties var p in obj1, so those indexes only necessarily exist in obj1. As such, trying to assign obj1[p] = obj2[p]; won't work as expected, since there is no guarantee (and in your particular example this is certainly the case) that obj[p] is defined. This assignment will simply assign undefined to indexes in obj1 that don't exist in obj2 and copy the values whose indexes do exist in obj2.
You need to loop over each object's properties separately (i.e. two loops), although this also isn't a good idea, since any values with the same index on both object will result in one being wiped out. What are you actually trying to achieve by this? It seems a very dangerous/volatile thing to do.

Related

Javascript Const object under Object.freeze() is still changing [duplicate]

I am trying to understand the Object.freeze method of ECMAscript.
My understanding was that it essentially stops changes to all the properties of an object. MDN documentation says:
Prevents new properties from being added to it; prevents existing properties from being removed; and prevents existing properties, or their enumerability, configurability, or writability, from being changed.
This does not seem to be the case, but perhaps I have misinterpreted the docs.
Here is my object, with its enumerable property exampleArray
function myObject()
{
this.exampleArray = [];
}
var obj = new myObject();
obj.exampleArray[0] = "foo";
Now if I freeze the object, I would expect the exampleArray property to be frozen too, as in it can no longer be changed in any way.
Object.freeze(obj);
obj.exampleArray[1] = "bar";
console.log(obj.exampleArray.length); // logs 2
"bar" has been added to the array, thus the frozen object has been changed. My immediate solution is to just freeze the desired property:
Object.freeze(obj.exampleArray);
obj.exampleArray[2] = "boo";
Now changing the array throws an error, as desired.
However, I am developing my application and I don't yet know what will be assigned to my object. My use case is that I have some game objects which are initialized (from an XML file) when the game starts. After this, I do not want to be able to change any of their properties accidentally.
Perhaps I am misusing the freeze method? I would like to be able to freeze the whole object, a sort of recursive freeze. The best solution I can think of here is to loop through the properties and freeze each one.
I've already searched for this question and the only answer says it's an implementation bug. I am using the newest version of Chrome. Any help is appreciated.
Object.freeze is a shallow freeze.
If you look at the description in the docs, it says:
Values cannot be changed for data properties. Accessor properties (getters and setters) work the same (and still give the illusion that you are changing the value). Note that values that are objects can still be modified, unless they are also frozen.
If you want to deep-freeze an object, here's a good recursive example
function deepFreeze(o) {
Object.freeze(o);
Object.getOwnPropertyNames(o).forEach(function(prop) {
if (o.hasOwnProperty(prop)
&& o[prop] !== null
&& (typeof o[prop] === "object" || typeof o[prop] === "function")
&& !Object.isFrozen(o[prop])) {
deepFreeze(o[prop]);
}
});
return o;
}
function myObject() {
this.exampleArray = [];
}
var obj = deepFreeze(new myObject());
obj.exampleArray[0] = "foo";
console.log(obj); // exampleArray is unchanged
Set the property descriptors for the object to writable:false, configurable:false using Object.defineProprties; then call Object.preventExtensions on the object. See How to create static array in javascript.

how many nested object should i define in javascript?

I am new in javascript.
Here I am wondering about how many nested or inner object could i
define in javascript
how to find first 2 nested object's key in js.
i also search it on google but i didn't get any solution.
here is example what i want!
var obj = {
a:{
b:{
c:{
//so on
}
}
}
}
thanks in advance.
Here I am wondering about how many nested or inner object could i define in javascript
There is no specified limit.
In the case of an object initializer such as the one you've shown, eventually you'll run into some sort of limitation of a particular JavaScript engine running the code, e.g., around its parsing / processing of the initializer, but nothing defined in the specification.
If you build objects dynamically on your own, for instance like this:
// Don't run this code!
var obj = {};
while (true) {
obj.child = {};
obj = obj.child;
}
...there's no reason to believe you'll run into anything other than a memory limit related to the number of objects you're creating (not their nesting).
how to find how many objects keys are defined in js
In one particular object, you can get an array of its own (not inherited) properties via Object.getOwnPropertyNames and Object.getOwnPropertySymbols, then take the length of the array. To find out how many properties the object has and how many the objects its properties refer to have, you'd use a recursive search — but beware of cyclic structures.
For instance:
const obj = {
a: {
b: {
c: {
}
}
}
};
function countProps(target, recursive = false) {
const ownProperties = [
...Object.getOwnPropertyNames(target),
...Object.getOwnPropertySymbols(target)
];
let count = ownProperties.length;
if (recursive) {
for (const key of ownProperties) {
const value = target[key];
if (value && typeof value === "object") {
count += countProps(value, true);
}
}
}
return count;
}
console.log(countProps(obj, true));
answer for first question.
There is not any restriction for nested object. you can define nested object as per you want until your memory limit exceed.
answer for second question.
here is a code to find keys from nested objects but it is work for only 2nd nested object.
for (var key in ob) {
if (!ob.hasOwnProperty(key))
continue;
var obj = ob[key];
help += "</br>"
for (var prop in obj) {
// skip loop if the property is from prototype
if(!obj.hasOwnProperty(prop)) continue;
help += " ---) \""+key+" "+prop+"\"</br>"
}
}
tell me if you got what you want.
Here I am wondering about how many nested or inner object could i define in javascript?
In the specification of JS it is not defined.
You can define nested or inner object how many you want.
But: do not forget: every object in your code need place in PC memory. And if you have to many objects you browser will not work correctly.
How to find how many objects keys are defined in JS?
With following metods:
Object.getOwnPropertyNames
Returns an array containing the names of all of the given object's own enumerable and non-enumerable properties.
Object.getOwnPropertySymbols
Returns an array of all symbol properties found directly upon a given object.
you will find the length of how many objects keys are defined in your object.

JavaScript array value to variable

I am trying to get into Fuse to create mobile apps and they use JavaScript for their logic. I never used JavaScript before and just recently completed their getting started course. Most of the stuff is pretty easy to understand, but I am having trouble with the way they use variables at one point. It would be nice, if somebody could explain how variables behave in JavaScript.
So the problem I have goes as follows:
for (var i = 0; i < hikes.length; i++){
// A new variable gets the value of the array
var hike = hikes[i];
if (hike.id == id){
// The variable gets a new value
hike.name = "foo";
break;
}
}
So, in my understanding of programming, the array hikes should be unchanged and only the variable hike should have foo as the name value. But in reality, the array now also has the name foo.
I guess the variable works as a pointer to the address of the arrays value, but maybe somebody can help me to better understand that concept.
Yes you're right, objects and arrays are always passed as references:
a = {}; // empty object
b = a; // references same object
b.foo = 'bar';
a.foo; // also 'bar'
You can create a deep copy of the array using JSON.parse(JSON.stringify(hikes)); and then use that copied array for manipulation:
var hikes = [
{
'id': 10
}
];
var id = 10;
var tempHikes = JSON.parse(JSON.stringify(hikes));
for (var i = 0; i < tempHikes.length; i++){
// A new variable gets the value of the array
var hike = tempHikes[i];
if (hike.id == id){
// The variable gets a new value
hike.name = "foo";
console.log('hike is ', hike);
break;
}
}
console.log(hikes);
arrays in javascript are passed by reference, whenever you modify an element in an array that change will occur anywhere you are accessing that array, to avoid such issues you have to use Array.from(arg) which creates a new array of from the arg parameter. This also applies to objects, to avoid such issues with objects, you have to use Object.create(obj) to create a new obj of from obj parameter or you can use let newObj = Object.assign( {} , obj ) , whenever you make any modification to the members of newObj the obj object does not see it, in other words there is no direct linkage between this two object, same thing applies for array
Boolean, null, undefined, String, and Number values are called primitive types.
When you assign something that is not a primitive type, namely arrays, functions and objects you are storing a reference to that.
That means that hikes[i] contains a reference to the object, where reference roughly means a pointer to it's location in memory.
When you assign hike = hikes[i] you are copying over the reference and not the actual object. So in fact hike still points to the same object as hikes[i], so any changes to that object are visible on both occasions.
If you want to copy the underlying object, there are different ways of doing so. One of them is Object.assign:
var hike = Object.assign({}, hikes[i])
This is because of pass by reference. All you need to do is create a new object (string, number ...) that you can work on.
for (var i = 0; i < hikes.length; i++){
var hike = hikes.slice(i,i+1)[0];
if (hike.id == id){
hike.name = "foo";
break;
}
}
slice also create a deep copy. you can use splice or assign or ((key1, key2)=>(key1, key2))(obj) etc.

Dive into getter/setters

I want to create objects which they will have an object named generic_object as their prototype object. generic_object must have a getter/setter property whose role will be to assign different functions to newly created objects. Virtually, that's the same how accessor property .onclick works. We may give different listeners to different DOM elements by just using the setter:
elem.onclick=function(){...};
I 've constructed the following:
var generic_object={
temp:null,
set onair(callback){
callback();
this.temp=callback;
},
get onair(){
return this.temp;
}
};
var obj1=Object.create(generic_object);
var obj2=Object.create(generic_object);
obj1.onair=function(){console.log(1);};
obj2.onair=function(){console.log(2);};
This does my job, however I want to eliminate .temp property because it is being created inside obj1 and obj2 as an own property (.temp inside generic_object is shadowed) and that's something I do not want.So:
Question1: Is it possible to transform the above code and get the same result without using temp?
Question2: Let's take the previous example.Since .onair property never becomes own property of obj1, obj2 (getter/setters are not shadowed), how JS engine tells between obj1.onair and obj2.onair? Are these function objects stored inside the memory spots reserved for each of the objects obj1 and obj2 even, I repeat, these are not their own properties? I am confused about that...
Thank you

What is the best way to check that multiple variables are set?

This is more of a general practices question.
The language I am working with is Javascript. I have a function that is getting an object with many variables (okay, just 10 variables). What is the best way to make sure this function is getting all the required variables and that they are all set?
I know, I know, why not just use a if statement. That's a big chunk of if statements! As I grow as a programmer, I know that may not be the best method for this. I'm looking for a shortcut actually. How would you check a large sum of variables for existence and non-blank values?
This is a pretty neat way of handling validation, I usually use this when checking for required fields in form inputs.
var theObj = { /* object loaded from server */ }
function checkTheObj(testObj)
{
var requiredKeys = ['key1', 'key2', 'key3'];
for(var keyPos = 0; keyPos < requiredKeys.length; keyPos++)
{
if(typeof(testObj[requiredKeys[keyPos]]) == 'undefined')
{
return false;
}
}
return true;
}
if(checkTheObj(theObj))
{
//do stuff
}
You can of course tweak this to return or throw an exception telling the first missing field (or use an internal array to return a list of all missing fields).
function objectHas(obj, properties) {
var len = properties.length
for (var i=0; i<len; i++) {
if (i in properties) {
if((!obj.hasOwnProperty(properties[i])) || (!obj.propertyIsEnumerable(properties[i]))) {
return false;
}
}
}
return true;
}
Usage:
if(objectHas(user, ["email", "password", "phone"])) {
console.log("awesome");
}
It's simple, but does the job.
Edit: On an ideal world you could extend the Object prototype for an even neater syntax such as if(object.has(["a", "b", "c"])), but apparently extending the Object prototype is the incarnation of evil so a function will have to do :)
First of all, you need to improve your understanding of these languages and learn the correct terminology.
There is no (single) language named "Javascript" at all. You are implicitly using several languages here (depending on the runtime environment), all of which are ECMAScript implementations, and one of which is Netscape/Mozilla JavaScript (in Mozilla-based software like Firefox).
An object does not have variables, it has properties (not: keys). Global code, function code, and eval code can have variables; that is a different (but similar) concept.
The function is not getting an object, it is being passed a reference to an object as argument.
As a programmer, you should already know that you can do repetitive tasks in a loop; the associated statements in ECMAScript implementations are for, for-in, while and do. So you do not have to write several if statements.
You can access the properties of an object in two ways, where property is the property name:
Dot notation: obj.property
Bracket notation: obj["property"]
The second one is equivalent to the first if the property name is an identifier, i.e. if it follows certain naming rules. If the property name is not an identifier or if it is variable, you have to use the second one. This also shows that all property names are string values. So you can store the name of a property as value of a variable or another property, and then access the variable or property in the property accessor. In the following, a property name (property) is stored in and used from a variable:
var propertyName = "property";
obj[propertyName]
Combining that with a loop allows you to iterate over certain properties of an object. Unfortunately, the solutions presented so far are flawed in two respects: A for-in statement iterates only over the enumerable properties of an object, and it does so in arbitrary order. In addition, it also iterates over the enumerable inherited properties (which is why one solution requires the hasOwnProperty() call).
A simple, sure and efficient way to iterate only over certain properties of an object in a defined order looks as follows:
var propertyNames = ['name1', 'name2', 'name3'];
for (var i = 0, len = propertyNames.length; i < len; ++i)
{
/* … */ myObject[propertyNames[i]] /* … */
}
This works because propertyNames refers to an Array instance, which encapsulates an array data structure. The elements of an array are the properties of the Array instance that have integer indexes from 0 to 65535 (232−1). Because indexes are not identifiers (they start with a decimal digit), you have to use the bracket property accessor syntax (some people misunderstand this and refer to all ECMAScript objects as "arrays", even call them "associative arrays" and […] the "Array operator"). Therefore, propertyNames[i] evaluates to the values of the elements of the array in each iteration as i is increased by 1 each time. As a result, myObject[propertyNames[i]] accesses the property with that name in each loop.
Now, to find out whether the property is set, you need to define what that means. Accessing a property that does not exist results in the undefined value (not in an error). However an existing property may also have the undefined value as its value.
If "not set" means that the object does not have the property (but may inherit it), then you should use hasOwnProperty() as used in Mahn's solution.
If "not set" means that the object does not have the property and does not inherit it, then you should use the in operator, provided that the object is not a host object (because the in operator is not specified for them):
if (propertyNames[i] in obj)
If "not set" means that the object either has or inherits the property, but the property has the undefined value, or the object neither has nor inherits the property, then you should use the typeof operator as used in Bob Davies' and aetaur's solutions (but the latter approach using Array.prototype.every() is less compatible as-is; that method was not specified before ECMAScript Edition 5, and is not available in IE/JScript < 9).
There is a third option with ECMAScript Edition 5.x, the Object.keys() method which (despite its name) returns a reference to an Array instance that holds the names of all not-inherited properties of the argument:
var propertyNames = Object.keys(obj);
/* continue as described above */
It is a good idea to emulate Object.keys() if it is not built-in, as this algorithm is frequently useful.
This expression returns true, if all variables from variableNameList (list of required variable names) set in object o:
variableNameList.every(function(varName){ return typeof o[varName] !== 'undefined'; });
You can use underscore _.all function instead of native every, and underscore _.isUndefined instead of typeof ....

Categories