I'm currently learning Javascript (I'm familiar with C# and Python), and currently the tutorial I'm reading is discussing comparison between two objects. In the coding I've done (I've had various projects), this sort of thing has never really been needed. Given that this might be important for the future, I thought I'd look for when/where to use object comparison, but all I can find are questions/answers on how it works, not why you should use it and when. I can't think of any situations off the top of my head where comparisons between primitives wouldn't be better, so any help in this area would be appreciated.
You would use it when you have two variables which refer to objects, and you want to see whether they refer to the same object. For example, with the window object, you can do
if (window !== window.top) {
console.log('This script must be running in an iframe!');
}
I can't think of any situations off the top of my head where comparisons between primitives wouldn't be better
Many objects (including window) can't just be converted to a unique primitive easily.
You may be able to use JSON.stringify to convert a plain object to a string, and then compare those strings, but this won't help you compare whether the objects are actually the same object in memory:
const obj1 = { prop: 'val' };
const obj2 = { prop: 'val' };
// They are not the same object
console.log(obj1 === obj2);
// But if you convert them to a primitive string first, you won't be able to tell
console.log(JSON.stringify(obj1) === JSON.stringify(obj2));
At the risk of a circular argument, you use it when you need to use it. :-)
I'd say it's roughly the same as in C#. In both cases, when you use an equality operator, it tests to see whether they're the same object (rather than separate but equivalent objects).
For instance, suppose you have an array of objects, and the contents of that array can change. Later, you have an object you should remove. You'd compare the object to remove with the objects in the array to see if you should remove it (often in a filter operation):
arrayOfObjects = arrayOfObjects.filter(obj => obj !== objToRemove);
Related
Are arrays merely objects in disguise? Why/why not? In what way(s) are they (such/not)?
I have always thought of arrays and objects in JS as essentially the same, primarily because accessing them is identical.
var obj = {'I': 'me'};
var arr = new Array();
arr['you'] = 'them';
console.log(obj.I);
console.log(arr.you);
console.log(obj['I']);
console.log(arr['you']);
Am I mislead/mistaken/wrong? What do I need to know about JS literals, primitives, and strings/objects/arrays/etc...?
Are arrays/objects merely strings in disguise? Why/why not? In what way(s) are they (such/not)?
Arrays are objects.
However, unlike regular objects, arrays have certain special features.
Arrays have an additional object in their prototype chain - namely Array.prototype. This object contains so-called Array methods which can be called on array instances. (List of methods is here: http://es5.github.com/#x15.4.4)
Arrays have a length property (which is live, ergo, it auto-updates) (Read here: http://es5.github.com/#x15.4.5.2)
Arrays have a special algorithm regarding defining new properties (Read here: http://es5.github.com/#x15.4.5.1). If you set a new property to an array and that property's name is a sting which can be coerced to an integer number (like '1', '2', '3', etc.) then the special algorithm applies (it is defined on p. 123 in the spec)
Other than these 3 things, arrays are just like regular objects.
Read about arrays in the spec: http://es5.github.com/#x15.4
Objects are an unordered map from string keys to values, arrays are an ordered list of values (with integer keys). That's the main difference. They're both non-primitive, as they're composed of multiple values, which also implies pass-by-reference in JavaScript.
Arrays are also a kind of object, though, so you can attach extra properties to them, access their prototype and so on.
In your revised example, you're only taking advantage of the fact that an array is actually an object, i.e. you can set any property on them. You shouldn't do that. If you don't need an ordered list of values, use a plain object.
Strings can be either primitive or objects, depending on how they were declared.
var str = 'yes';
Gives you a primitive, while,
var str = new String('yes');
will give you a String object.
All arrays are the same (Whether or not they were defined with [] or new Array()), are of the type object and inherit from the "Array" object's prototype. There aren't real classes in Javascript, everything is an object, and there's a system defined object called Array. It has a property called 'prototype' (of type object), and when you use the new keyword on an object with a prototype property, it creates an instance with a reference to the contents of the prototype and stores it in your variable. So all arrays you've ever used in Javascript are objects and instances of Array's prototype property.
In any case, although arrays really are objects, they behave like arrays because of their useful properties and functions (Such as length, slice, push etc).
Another note, although I said there are no classes, when you do this:
console.log(Object.prototype.toString.call(your_object));
it will give you a string in the form [object Object]. But what's useful is that when you call it with an array, you get [object Array] same with functions which give [object Function] and a number of other system defined types, which assists in differentiating between normal objects and arrays (Since the typeof operator will always just return the string 'object').
Try this
var a = Array;
and go into firebug and examine the contents of a, especially it's 'prototype' property.
Edit: Changed the wording a bit, to be more correct. In fact when you use the new keyword, it creates an instance which references the prototype object. So any changes made to the prototype after the instance's declaration, will still affect the instance.
Edit: In answer to your latest revised question (are arrays/objects actually strings in disguise): No. They are objects, as I've explained. Strings are either a primitive type, or an object type (An instance of the String object) which contains the primitive equivalent as one of it's properties.
Arrays are not primitives in Javascript, they are objects. The key difference is that as a result, when you pass an array to a function it is passed by reference, not by value.
So yes! Arrays are objects in javascript, with a full blown Array.prototype and everything (don't touch that though...)
The confusion comes from the fact that javascripts lets you access object attributes in two ways:
myObj.attribute
or
myObj["attribute"]
Really what makes an array an array has nothing to do with the way you store data -- any object can store values using the syntax you use to store the array -- what makes an array an array is the fact that array methods (e.g. shift() and sort()) are defined for Array.prototype.
Trying to be brief with what I believe to be of the most significance: arrays have a number of methods that objects do not. Including:
length
push
pop
An object declared as var x = {foo:bar} has no access to a .length() method. They are both objects but with the array as a sort of superset with methods mentioned as above.
I don't feel I this is even close to being of Crockford standard in terms of explanation but I'm trying to be succinct.
If you want to get some quick results, open up Firebug or your javascript Console and try Array.prototype and Object.prototype to see some details
Update: In your example you declare an array and then do:
foo['bar'] = 'unexpectedbehaviour';
will produce unexpected results and won't be available in simple loops such as:
var foo=[0,1];
foo['bar'] = 2;
for(var i=0;i<foo.length;i++){
console.log(foo[i]);
}
//outputs:
//0
//1
An array can accept foo['bar']=x or foo.bar=y like an object but won't necessarily be available to be looped through as highlighted above.
Not that I'm saying that you can't iterate through the properties of an object, just that when working with an Array, you're utilising that unique functionality and should remember not to get confused.
In JavaScript you have a few types, everything else is an object. The types in JavaScript are: boolean, number, and string. There are also two special values, "null" and "undefined".
So the quest "is a JavaScript array an object?" is slightly ambiguous. Yes, a JavaScript array is an "object" but it is not an instance of "Object". A JavaScript array is an instance of "Array". Although, all objects inherit from Object; you can view the inheritance chain on the MDC. Additionally, arrays have slightly different properties than an object. Arrays have the .length property. They also have the .slice(), .join(), etc methods.
Douglas Crockford provides a nice survey of the language's features. His survey discusses the differences you are asking about. Additionally, you can read more about the difference between literals and constructors in question #4559207.
Arrays are Objects, but of a specialized nature. Objects are collections of values indexed by keys (in Javascript notation, {'key': 'value'}), whereas Arrays are Objects whose keys are numeric (with a few functions and properties). The key difference between them is obvious when you use a for each loop--an Object will iterate over all the values in its properties, whereas an Array will return the keys instead. Here's a link to a JSFiddle demonstrating the difference--notice that the first for each, which uses an array, returns the indexes, not the values; in contrast, the second for each returns the actual values at those keys.
My understanding of the data type is as follows. If we consider a machine like a mill that can take in rice, barley, corn, kidney beans, chickpeas, black beans, etc. So I understand the mill to be the program that processes data such as rice, barley, etc. The data are rice, barley, beans but they differ in types. Rice is of a different type than barley etc.
In javascript, i noticed objects mentioned under data types.
https://javascript.info/types#objects-and-symbols
It makes sense that 23 is data of type number, "cat" is data of type string, true is data of type "boolean" but object seems to be more like a data container rather than a data type. For instance, typeof([]) says it is an object. Now array seems like a data container rather than data and type of a data container doesn't make sense. To me, it makes sense that a data can have a type but a container where we put data having a type is confusing.
So I appreciate if someone can enlighten me. Array seems to be a container and not data and cannot have a type.
I appreciate any guide. Thanks!
On a general, theoretic level, an object consists of data that describes the object, and behaviours that act on that object. Before Object Oriented Programming, data was data, and code was code; if you needed to load some data, and draw it on the screen, chances are those two pieces of code would be in different places of your code base. OOP brings data and behaviour together for better conceptual organisation. It also allows some objects to share behaviour by sorting them into classes (e.g. "barking" is not something that needs to be coded for every dog individually) or by creating object prototypes (same idea, different approach). Furthermore, it allows different objects to specify different ways of performing the same behaviour (e.g. both cats and wolves know about hunting, though they go about it differently).
On a mechanical JavaScript-specific level, "object" is a data structure that can store various values under string keys. It is thus superficially similar to arrays, which again store values, but under integer keys.
However, "value" in JavaScript also includes functions, which is how JS object achieves the first objective (being a repository of related data and code that governs its behaviour). The second objective is achieved by prototypal inheritance:
let Mammal = function() {
}
let typicalMammal = new Mammal();
typicalMammal.legs = 4;
Mammal.prototype = typicalMammal;
let Dog = function() {
};
let typicalDog = new Mammal();
typicalDog.sound = function() { console.log("woof") };
Dog.prototype = typicalDog;
let fido = new Dog();
fido.colour = "yellow";
console.log("Fido:", fido);
fido.sound();
The third is also achieved: if we had a cat, we could just tell happy.sound() and it would do a "meow". We don't need to know if something is a dog or a cat, just that they know how to make a sound, and dynamic dispatch will do the rest.
It is also of note that when you invoke a function in an object with a dot notation like this, the function is interpreted as "method" - a function that knows which object it is acting on, by setting a special variable this. In this case, within the method sound, this would have the same value as fido.
Specifically with arrays, they are a kind of object that knows how to contain multiple values indicated by an integer index, how to be indexed, how to tell its length, how to iterate on its elements etc.
However, note that "variable" is something different entirely. One could conceptualise that variable is a data structure with a name and a value; but you can't typically access variable's name. A variable is not a value itself; you can't put a variable into a data structure, just copy its value there. It is more of a language artifact than a data type.
ECMAScript standard defines eight data types, 7 primitive types and Object.
In JavaScript, objects are a collection of properties and property values can be values of any type, for example an object with an attribute of type "number".
let obj = { num: 3 }
and you can test
typeof obj.num
will return "number", but
typeof obj
will return "object" I suppose because inheritance of prototype Object
All objects in JavaScript are descended from Object, all objects inherit methods and properties from Object.prototype.
In your example of an array. In javascript the array variable has a prototype of Array but that's an object that has a prototype of Object.
typeof([])
I think that's why is returning you "object".
Here are some links about data structures:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
JavaScript has only one data type for containers and it's called "object".
Arrays are containers and so their data type is "object". Like arrays there are other kinds of specialist object classes such as "function" (they contain code and are callable), sets and weak sets for example.
Significantly the JavaScript typeofoperator does not always return the data type of its operand. This is due to early implementation details of the operator which can not now be changed - and programs have long since adjusted to the actual implementation:
typeof null returns "object". The data type of null is "null".
typeof function returns "function". The data type of a function is "object".
...variable is a container and is not data
Variables are not so much a container as an identifier of where a value is stored. Variables in JavaScript are weakly typed which means the data type of a value is not determined by the variable (or object property) to which a value has been assigned but by the internal memory construct used to hold the value. That is to say, type is obtained from the value stored, not the variable used to access it.
Object values
An object value stored in a JavaScript variable is some kind of memory pointer to a data structure whose location and implementation details are private and only known to the JavaScript engine.
It makes sense to call objects values a data type in JavaScript for the same reason pointers in C have a data type depending on what they point to. It also explains why if you assign the same "object value" to two variables, they will both then point to the same object data set held at some unknown location in memory.
The major difference with JavaScript object values is that you can't perform pointer arithmetic on them and must rely on object property notations object.propertyName or object["propertyName"] to directly access properties of an object.
Array objects
JavaScript arrays are objects which use positive integer values, converted to a string, to access array entries being held as string properties of the array object.
Unlike a typed array, index values to access entries of an Array object do not have an upper bound nor do they need to be consecutive - memory is not allocated to store entries which have not been set.
TLDR;
JavaScript arrays are implemented as associative lookup tables. Their data type is "object" and they inherit properties and methods from Array.prototype and Object.prototype.
They are called "exotic" objects in ECMAScript standards because they monitor access to see if the property name used represents a non-negative integer and maintain the array object's length property if it is.
Early JavaScript documentation went out its way not to mention pointers, presumably to avoid confusing BASIC programmers. Documentation used "object" to mean a data structure, object values were stored as pointers, and the short hand property access operator chosen was . instead of the -> operator for pointer access used in the C language family.
Ref: MDN Maps
Use maps over objects when keys are unknown until run time, and when
all keys are the same type and all values are the same type.
Use objects when there is logic that operates on individual elements.
Question:
What is an applicable example of using Maps over objects? in particular, "when would keys be unknown until runtime?"
var myMap = new Map();
var keyObj = {},
keyFunc = function () { return 'hey'},
keyString = "a string";
// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");
console.log(myMap.get(keyFunc));
What is an applicable example of using Maps over objects?
I think you've given one good example already: You at least need to use Maps when you are using objects (including Function objects) as keys.
in particular, "when would keys be unknown until runtime?"
Whenever they are not known at compile time. In short, you should always use a Map when you need a key-value collection. A good indicator that you need a collection is when you add and remove values dynamically from the collection, and especially when you don't know those values beforehand (e.g. they're read from a database, input by the user, etc).
In contrast, you should be using objects when you know which and how many properties the object has while writing the code - when their shape is static. As #Felix has put it: when you need a record. A good indicator for needing that is when the fields have different types, and when you never need to use bracket notation (or expect a limited set of property names in it).
I think that with ES2015's Map only two reasons are left to use plain objects:
You don't want to iterate over the properties of an object type at all
or you do but the property order doesn't matter and you can distinguish the program from the data level when iterating
When is the property order unimportant?
if you have only a single value and some functions that should be associated explicitly with it (like Promise - which is a proxy for a future value - and then/catch)
if you have a struct/record-like data structure with a static set of properties known at "compile time" (usually structs/records aren't iterable)
In all other cases you might consider using Map, because it preserves property order and separates the program (all properties assigned to the Map object) from the data level (all entries in the Map itself).
What are the drawbacks of Map?
you lose the concise object literal syntax
you need custom replacers for JSON.stringyfy
you lose destructuring, which is more useful with static data structures anyway
Use maps over objects when keys are unknown until run time, and when all keys are the same type and all values are the same type.
I have no idea why someone would write something so obviously wrong. I have to say, people are finding more and more wrong and/or questionable content on MDN these days.
Nothing in that sentence is correct. The main reason to use maps is when you want object-valued keys. The idea that the values should be the same type is absurd--although they might be, of course. The idea that one shouldn't use objects when keys are unknown until run time is equally absurd.
One of the difference between Map and Object is:
Map can use complex data type as its key. like this:
const fn = function() {}
const m = new Map([[document.body, 'stackoverflow'], [fn, 'redis']]);
m.get(document.body) // 'stackoverflow'
m.get(fn) //'redis'
watch out: For complex data type, If you want to get the value, you must pass the same reference as the key.
Object, it only accept simple data type(number, string) as its key.
const a = {};
a[document.body] = 'stackoverflow';
console.log(a) //{[object HTMLBodyElement]: "stackoverflow"}
Objects are similar to Maps in that both let you set keys to values, retrieve those values, delete keys, and detect whether something is stored at a key. Because of this (and because there were no built-in alternatives), Objects have been used as Maps historically; however, there are important differences that make using a Map preferable in certain cases:
The keys of an Object are Strings and Symbols, whereas they can be
any value for a Map, including functions, objects, and any primitive.
The keys in Map are ordered while keys added to object are not. Thus,
when iterating over it, a Map object returns keys in order of
insertion.
You can get the size of a Map easily with the size property, while
the number of properties in an Object must be determined manually.
A Map is an iterable and can thus be directly iterated, whereas
iterating over an Object requires obtaining its keys in some fashion
and iterating over them.
An Object has a prototype, so there are default keys in the map that
could collide with your keys if you're not careful. As of ES5 this
can be bypassed by using map = Object.create(null), but this is
seldom done.
A Map may perform better in scenarios involving frequent addition and
removal of key pairs.
MDN
This question is a duplicate of but until it's closed, here's my answer from over there:
In addition to the other answers, I've found that Maps are more unwieldy and verbose to operate with than objects.
obj[key] += x
// vs.
map.set(map.get(key) + x)
This is important, because shorter code is faster to read, more directly expressive, and better kept in the programmer's head.
Another aspect: because set() returns the map, not the value, it's impossible to chain assignments.
foo = obj[key] = x; // Does what you expect
foo = map.set(key, x) // foo !== x; foo === map
Debugging maps is also more painful. Below, you can't actually see what keys are in the map. You'd have to write code to do that.
Objects can be evaluated by any IDE:
Well, I am not sure if I describe the problem clearly, currently I am using ExtJS to do some developing, I saw some objects are "singleton", such as "Ext.Viewport", In C++, I can get the address of the object to see if they are actually same object, in Python, I can use "id" function to get the hash code of the object, and In Java I have similar built-in function "hashCode" to check if the objects are really same object, is there similar ways in javascript for this? so if there are some functions or operator in javascript, then I can tell if the object in ExtJS defined as "singleton" is really referencing to the same object.
You don't need anything so complicated. If two values are the same object, then they will be equal.
var foo = {};
var bar = foo;
alert(foo == bar);
If they are different (even if identical) objects, they won't be.
var foo = {};
var bar = {};
alert(foo == bar);
Your question is not very clear, but I'll try to answer.
Javascript itself does not use unique identifiers for each object by default. You could add this if you wanted to.
Depending on your requirements, you could also use the typeof operator to compare the type.
ExtJs however, does use unique id's (either id or itemId) and also allows you to get the class name of the object that your using. So you could do this easily in ExtJs.
The answer depends on whether you are comparing the type of object, or the actual object instance itself.
This other SO answer may be beneficial
I think that I'm understanding you... but, did you check this JavaScript comparator ?
=== - equal value and equal type
!== - not equal value or not equal type
reference: Javascript comparators
If you want to know if two object references refer to the same single object instance, use ==.
If you want to do a deep comparison of the referenced objects to see if the objects contain all the same values, even if they are not the same object instance, use Lodash's _.isEqual(a, b) method.
could also convert both to json, and use something like jsonDiff: https://github.com/pkafel/json-diff
My JavaScript code stores a lot of data in arrays. I want to retrieve a key using something similar to what I wrote below. It key that should be retrieved is based on variables that are page-dependent . The following code doesn't work. Can anyone give me a solution to this problem?
This is part of a script that does automatic conjugation. (looks for SUBJECT in a div and then looks for VERB in another div and then conjugates the verb by retrieving the conjugated form from the array)
function getarray(Array,Key) {
return Array[Key];
}
Example of how it should work:
verb = innerhtmlfromdiv;
subject = innerhtmlfromotherdiv;
function getarray(Array,Key) {
return Array[Key]; }
conjugatedverb = getarray(verb,subject);
htmltextbox.value = conjugatedverb;
First off, what you want is an Object, not an Array. I'm guessing that you're new to javascript and your previous language was either PHP or PERL, and so you think what you're using is an "Associative Array".
The basics: There is no such thing as Associative arrays in Javascript. There is Objects, and a non-primitive subclass of Object called Array, which has some methods for dealing with Numericly named object properties, and a magic length property.
Since the keys you are dealing with are strings, not numbers, you have no use for Arrays.
Javascript Objects on the other hand are similar to an Associative array in php, or a hash in perl. (but they are not exactly the same thing).
As you have no doubt discovered, with an Object, you can use subscript notation to access certain properties, as in
verbs["go"] = "went";
this is equivilent to
verbs.go = "went";
a common mistake is to think that the dot notation is only used for objects, and the subscript notation for "associative arrays", because this is how it works in PHP. In javascript the two notations are interchangable. Since Arrays are a subclass of Object, the above examples work on them as well (but they don't use any special properties of Arrays).
As for your specific problem:
You need an object full of objects.
so for instance
var verbs = {
"do":{"Truck":"Drive","Blender":"Turn On","Bike":"Ride"},
"take":{"Money":"Steal","Julie":"Accompany","Lever":"Pull}
}
then your function would be:
function conjugate (verb, subject) {
return verbs[verb][subject];
}
and an example of its use would be
conjugate("do","Truck") // returns "Drive"
Try changing the parameter name Array to something else. Array is the name of a built-in function/object in javascript.
I don't quite get the point of the function. This is like writing:
function getValue(var) {return var}
Why not just get the value the normal way without wrapping it in a useless function:
conjugatedverb = verb[subject];
htmltextbox.value = conjugatedverb;
Also, your code doesn't make sense when you claim to do an innerHTML from an element and somehow get an object instead of a string. What is really going on? I think your problem starts even before this snippet of code.