I've got a simple array cars of Parse models of class Cars
When I do
var uniqCars = _.uniq(cars);
it doesn't work. uniqCars is exact same as cars. The length of cars is 5 and length of uniqCars is 5 (when it should be 2).
However, when I do:
var uniqCars = _.uniq(cars,
function (c) {
return c.id;
});
It works. My question is, why doesn't it work with the former and works with the latter? Why do I have to be so verbose? Is this an issue with Parse or underscore?
why doesn't it work with the former
because, if you don't pass the comparator function, it by default uses === operator to compare the objects. Quoting the _.uniq documentation,
Produces a duplicate-free version of the array, using === to test object equality. ... If you want to compute unique items based on a transformation, pass an iteratee function
When you use === (Strict Equality operator), no two objects will be the same unless they are one and the same object or same sequence of characters forming a string. For example,
console.assert(({} === {}) === false);
var obj = {};
console.assert(obj === obj);
console.assert("ab" === "a" + "b")
console.assert("ab" === 'a' + "b")
So, it is not specific to Parse but it is the expected behaviour in JavaScript.
The comparisons are made using strict equality. Unless there are multiple references to the same object in the array, they are not going to be strictly equal.
Produces a duplicate-free version of the array, using === to test object equality. In particular only the first occurence of each value is kept. If you know in advance that the array is sorted, passing true for isSorted will run a much faster algorithm. If you want to compute unique items based on a transformation, pass an iteratee function.
Related
I do not mean deep comparison.
I just want to know if two variables refer to the same instance. Should I use a==b or a===b? Can two variables point to the same memory but with different types? Because javascript has no such concept as class in C++, I do not know what an object's type is. Do all objects have the same type: "object" so === decides their types are equal? If so, === would be the same as ==.
From A Drip of Javascript: Object Equality in Javascript:
... Primitives like strings and numbers are compared by their value, while objects like arrays, dates, and plain objects are compared by their reference. That comparison by reference basically checks to see if the objects given refer to the same location in memory. Here is an example of how that works.
var jangoFett = {
occupation: "Bounty Hunter",
genetics: "superb"
};
var bobaFett = {
occupation: "Bounty Hunter",
genetics: "superb"
};
var callMeJango = jangoFett;
// Outputs: false
console.log(bobaFett === jangoFett);
// Outputs: true
console.log(callMeJango === jangoFett);
you should use === because it will avoid error exceptions hard to be found. and about time consuming, === is better as well.
I am confused about placement of operators:
Given:
var a = [0, 1, 2];
So far as I can tell, each of the following is correct:
var len = a.length;
var lastElt = a.pop();
var str = String(a);
var typeStr = typeof a;
Is there an easy way to remember/think about whether the operator goes before or after the operand and whether it requires parentheses? Or is it simply rote memorization?
Thanks.
Let's go:
case #1
var len = a.length;
In this case you're calling the method lenght of the array store in the variable a.
case #2
var lastElt = a.pop();
As before, here you're calling the method pop of the array.
case #3
var str = String(a);
You aren't not calling any array's method. Here you're casting the array. i.e. you are stringifying the array.
case #4
var typeStr = typeof a;
Here you also aren't calling any array's method. You are calling the typeof method of the window object and passing the array a as an argument.
As you can see. In the first two cases, you are calling array's methods. In the last two cases, you are calling window object's methods and passing your array as an argument.
Your list there mostly consists of things that are not operators:
length is a property belonging to Array objects. It returns the number of items in the Array.
pop() is a method belonging to Array objects. It removes the last item from the Array and retuns it.
String() is a global object which is the constructor for a String object. It takes any object as a parameter and converts it to a String
typeof is an operator. It returns a string that indicates the type of the subsequent operand.
For more reference, here is some information about JavaScript operators.
I highly recommend searching Google for some beginning JavaScript tutorials so you can learn the basic concepts.
Thanks for all the prompt replies. In reply to the question 'What do you mean by "operator" here?' I come from a background of mathematics and (lately) c programming. By "operator" I wanted to speak abstractly about anything that mapped its argument to something useful, using it to include methods, properties, etc., without enumerating them. My attempt to abstract these is probably the source of my confusion. I now understand that what is required is rote memorization, something like declensions in Latin ;-).
Operators refer to +,=*,/ etc.
I don't think there is an easy way to remember. If it is a 'property', there will be no parentheses. If it is a function, there will be parentheses. I always remember that length is a property of an array, and that push and pop are actions you can do to the array. Type casting always starts with the 'type' capitalized followed by what you want casted in the parenthesis. typeof is just a weird one.
Can somebody please explain the following passage from YDKJS Up & Going to me like I am five:
You should take special note of the == and === comparison rules if
you're comparing two non-primitive values, like objects (including
function and array). Because those values are actually held by
reference, both == and === comparisons will simply check whether the
references match, not anything about the underlying values. For
example, arrays are by default coerced to strings by simply joining
all the values with commas (,) in between. You might think that two
arrays with the same contents would be == equal, but they're not:
var a = [1,2,3];
var b = [1,2,3];
var c = "1,2,3";
a == c; // true
b == c; // true
a == b; // false
What is meant by "references"? Does this mean where the array is held in memory?
well yeah,
you see when you create array named 'arr' for example.
your memory look like this:
so reference comparison actually check if the array reference point the same array in the heap.
stack is for value types and references.
I was perusing the underscore.js annotated source when I encountered this:
if (obj.length === +obj.length) {...}
I now know from this stackoverflow question that the plus sign (+) operator returns the numeric representation of the object.
That said, obj.length returns a number. When would obj.length not be equal to +obj.length?
The === operator does not make any typecast when it checks, so different types of data will immediately return false even if '5' == 5. The + as you said typecasts the object into number. If you typecast a number into a number, it is still a number, so you basically check if your object.length exists and is a number. Values like undefined, NaN, null, string and others will return false. You are not sure what happens with obj, so you have to check...
When, for example:
var obj = {
0: 'first',
length: '1'
};
alert(obj.length === +obj.length);
Underscore's each is a generic, therefore can work with other objects other than an array. Just like ECMA5 forEach
The forEach function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the forEach function can be applied successfully to a host object is implementation-dependent.
So underscore are checking the validity of an object's length property. And they deem an object arrayLike, for that method of iteration, only if the object's length returns a number which is not NaN, and is certainly not a string. So in my above example, obj would fall through to their keys iteration, if there is no native/polyfilled forEach.
I have a list of index positions in a variable called positions, I want to find the index of one of the positions like...
positions[0]
(2) [0, 0]
positions.indexOf([0,0]);
-1
var item = positions[0]
undefined
item
(2) [0, 0]0: 01: 0length: 2__proto__: Array(0)concat: ...
positions.indexOf(item);
0
What would be the way to use indexOf in this case?
The indexOf method uses strict comparison to find its match. This is the same comparison algorithm used by ===, and it compares identity of object types (like Array). So when you pass [0,0], you're passing a new object with its own identity, so no match is found.
That's why it works when you search specifically for the item at index 0. You're now finding the Array with the same identity.
To make it work the way you want, you'll need to use a custom object comparison that takes into account the members of the Array. JavaScript has nothing like this built in, but you'll find solutions if you search for "deep equality comparison".
Once you have the comparison function, you can use .findIndex() to run it on each object.
var data = [0, 0];
var result = positions.findIndex(function(item) {
// return result of comparing `data` with `item`
// This simple implementation assumes that all `item`s will be Arrays.
return data.length === item.length &&
item.every(function(n, i) { return n === data[i] });
});
Strictly speaking, if the members of positions are all Arrays with numbers as members, you could use JSON.stringify() to do the comparison. But don't trust it if the members being compared are of other object types. It may seem to work, but could fail without notice.
var data = JSON.stringify([0, 0]);
var result = positions.findIndex(function(item) {
return data === JSON.stringify(item);
});