How can you check if two or more objects/vars have the same reference?
You use == or === :
var thesame = obj1===obj2;
From the MDN :
If both operands are objects, then JavaScript compares internal
references which are equal when operands refer to the same object in
memory.
The equality and strict equality operators will both tell you if two variables point to the same object.
foo == bar
foo === bar
For reference type like objects, == or === operators check its reference only.
e.g
let a= { text:'my text', val:'my val'}
let b= { text:'my text', val:'my val'}
here a==b will be false as reference of both variables are different though their content are same.
but if I change it to
a=b
and if i check now a==b then it will be true , since reference of both variable are same now.
As from ES2015, a new method Object.is() has been introduced that can be used to compare and evaluate the sameness of two variables / references:
Below are a few examples:
Object.is('abc', 'abc'); // true
Object.is(window, window); // true
Object.is({}, {}); // false
const foo = { p: 1 };
const bar = { p: 1 };
const baz = foo;
Object.is(foo, bar); // false
Object.is(foo, baz); // true
Demo:
console.log(Object.is('abc', 'abc'));
console.log(Object.is(window, window));
console.log(Object.is({}, {}));
const foo = { p: 1 };
const bar = { p: 1 };
const baz = foo;
console.log(Object.is(foo, bar));
console.log(Object.is(foo, baz));
Note: This algorithm differs from the Strict Equality Comparison Algorithm in its treatment of signed zeroes and NaNs.
Possible algorithm:
Object.prototype.equals = function(x)
{
var p;
for(p in this) {
if(typeof(x[p])=='undefined') {return false;}
}
for(p in this) {
if (this[p]) {
switch(typeof(this[p])) {
case 'object':
if (!this[p].equals(x[p])) { return false; } break;
case 'function':
if (typeof(x[p])=='undefined' ||
(p != 'equals' && this[p].toString() != x[p].toString()))
return false;
break;
default:
if (this[p] != x[p]) { return false; }
}
} else {
if (x[p])
return false;
}
}
for(p in x) {
if(typeof(this[p])=='undefined') {return false;}
}
return true;
}
Related
This is a follow up to my questions on the Arguments Optional Challenge in Freecodecamp (see below0:
I have now satisfied 5/6 conditions of the challenge, except for when the input is addTogether(2,([3])), which returns '23' as a string instead of the correct 'undefined'.
If the [3] is an array, and an array is an object, shouldn't my checkNum function work to label that as undefined? Where was the string generated?
my code now:
function addTogether() {
function checkNum(x) {
return typeof x === 'number' ? x : undefined;
}
let num1 = checkNum(arguments[0]);
let num2 = checkNum(arguments[1]);
if (arguments.length === 1) {
if (typeof num1 === 'number') {
let a = num1;
return function (b) {
return a + b;
};
}
return undefined;
}
if (arguments.length > 1) {
if (typeof num1 !== 'number' || typeof num2 !== 'number') {
return undefined;
}
if (typeof num1 === 'number' && typeof num2 === 'number');
{
return arguments[0] + arguments[1];
}
}
}
THANKS
//original question below:
I am stuck on the freecodecamp problem Arguments Optional.
https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/arguments-optional
In researching the problem, there have been multiple references to the following code-block, but I just can't get my head around what it means:
if(arguments.length==1){
if (typeof a == "number"){
return function(b){
if (typeof b == "number"){
return a + b;
}
};
}
}
I understand up to the 'return function(b)' part, then my brain melts.
If someone could please explain it as if to a 6-year-old, this noob would really appreciate the help.
This is quite common practice to return a function instead of a value.
When the outer function (which is supposed to do addition) is called with one argument, instead of doing addition (can't do) it is returning a function. When that function is called subsequently with a number parameter it executes the function b and does the sum.
Let us say the outer function name is add() so it can be triggered the following ways:
add(10, 15); // 25
var f = add(20);
f(18) // 38
add(4)(6) // 10
Full example:
function add(a, b) {
if (arguments.length == 1) {
if (typeof a == "number") {
return function (b) {
if (typeof b == "number") {
return a + b;
}
};
} else {
return "undefined";
}
} else if (arguments.length == 2) {
if (typeof a == "number" && typeof b == "number") {
return a + b;
} else {
return "undefined";
}
} else {
return "undefined";
}
}
console.log(add(10, 15));
var f = add(20);
console.log(f(18));
console.log(add("xyz"));
console.log(add(10, "5"));
console.log(add(4)(6));
We can declare functions in 2 ways, the regular way:
function test(){
}
or the interesting way
let test = function(){
}
in this case, the function is returning a function
see here:
function returnfunction(){
return function(b){
if (typeof b == "number"){
return a + b;
}
}
}
let x = returnfunction()
So, x is the return value of returnfunction, which is
function(b){
if (typeof b == "number"){
return a + b;
}
}
So similar to above,
x = function(){
//...
}
I have a function that receives 2 arguments and 1 additional, optional argument. The function must return true if the first argument is bigger than the second one, false if not, except if the third argument is true (the third argument can be only true or false, false by default), in which case the function should return true if the first argument is either bigger or equal (strict comparison) to the second argument.
The function isn't guaranteed to receive arguments of the same type, or even arguments that make any sense (the function could be called with null, undefined). Anyways, the function must obey javascript behavior to compare the received arguments.
I have two functions, and I believe the second one should be faster, but neither my own benchmarks nor jsperf results say so. In fact, the first function is ~30-35% faster, which is quite a lot.
How can I track down the slow code paths inside each function? How can I know why the second function is slower?
This is my benchmark:
var microtime = require('microtime');
/* Helper functions */
function maybeBool() {
if(Math.round(Math.random() * 1)) {
return true;
} else {
return false;
}
}
function maybeNullUndef() {
if(Math.round(Math.random() * 1)) {
return null;
} else {
return undefined;
}
}
function randomString() {
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
}
function randomDate() {
var y = Math.round(Math.random() * 100);
return new Date(y);
}
function something() {
var x = Math.round(Math.random()*3);
switch(x) {
case 0:
return maybeBool();
break;
case 1:
return maybeNullUndef();
break;
case 2:
return randomString();
break;
case 3:
return randomDate();
break;
}
}
var things_to_compare = [];
for(i = 0; i < 500000; i++) {
var a = something();
var b = something();
things_to_compare.push([a, b]);
}
/* First function */
function gtHelper(prop1, prop2, equal) {
// 'falsy' and Boolean handling
if (!prop1 || !prop2 || prop1 === true || prop2 === true) {
if ((prop1 === true || prop1 === false) && (prop2 === true || prop2 === false)) {
if (equal) {
return prop1 === prop2;
} else {
if (prop1) {
return !prop2;
} else {
return false;
}
}
}
if (prop1 === undefined || prop1 === null || prop1 === false || prop2 === true) {
return !!equal || false;
}
if (prop2 === undefined || prop2 === null || prop1 === true || prop2 === false) {
return true;
}
if (prop1 > prop2) {
return true;
}
if (prop1 < prop2) {
return false;
}
// not lt and and not gt so equality assumed-- this ordering of tests is date compatible
return equal;
}
if (prop1 > prop2) {
return true;
}
if (prop1 < prop2) {
return false;
}
// not lt and and not gt so equality assumed-- this ordering of tests is date compatible
return equal;
}
/* Second function */
function gtHelper2 (prop1, prop2, equal) {
equal = !!equal;
//If 'prop1' is any of those, the result will be always 'false',
//unless 'equal' is true.
switch (prop1) {
case "":
case null:
case false:
case undefined:
return (prop1 === prop2 && equal);
}
//If 'prop2' is any of those, the result will be always 'true'
switch (prop2) {
case "":
case null:
case false:
case undefined:
return true;
}
if (prop1 > prop2 || (prop1 === prop2 && equal)) {
return true;
} else if (prop1 < prop2) {
return false;
} else {
return equal;
}
}
/* Benchmark */
var res1 = 0;
for(n = 0; n < 30; n++) {
var now = microtime.now();
for(i = 0; i < 500000; i++) {
gtHelper(things_to_compare[i][0], things_to_compare[i][1]);
}
var now1 = microtime.now();
res1 += now1 - now;
}
var res2 = 0;
for(n = 0; n < 30; n++) {
var now = microtime.now();
for(i = 0; i < 500000; i++) {
gtHelper2(things_to_compare[i][0], things_to_compare[i][1]);
}
var now1 = microtime.now();
res2 += now1 - now;
}
console.log("gtHelper:", res1/30);
console.log("gtHelper2:", res2/30);
Edit:
I have been further working on the second function, I achieved make it a little bit faster, but it keep lagging behind the first function.
This is how it looks now:
function gtHelper2 (prop1, prop2, equal) {
//If 'prop1' is any of those, the result will be always 'false',
//unless 'equal' is true.
if (!prop1) {
return (prop1 === prop2 && !!equal);
}
//If 'prop2' is any of those, the result will be always 'true'
if (!prop2) {
return true;
}
if (prop1 > prop2) {
return true;
} else if (prop1 < prop2) {
return false;
} else if (prop1 === prop2 && !!equal) {
return true;
} else {
return !!equal;
}
}
Your two functions do not return the same thing.
gtHelper(true, 'string') // true
gtHelper2(true, 'string') // false
gtHelper('string', new Date()) // undefined
gtHelper2('string', new Date()) // false
gtHelper(new Date(), 'string') // undefined
gtHelper2(new Date(), 'string') // false
If you can get these functions behaving the same, I am sure you will see more meaningful results.
You should be aware that, in the browser at least, you should not expect switch to perform the same on all platforms. You should read the ECMA spec on switch to see why optimising this should be so difficult. I know that Firefox did spend a good deal of time on making their switch implementation perform well. I've heard nothing about anything similar on V8.
I have a function to return if a variable/object is set or not:
function isset() {
var a = arguments, l = a.length;
if (l === 0) { console.log("Error: isset() is empty"); }
for (var i=0; i<l; i++) {
try {
if (typeof a[i] === "object") {
var j=0;
for (var obj in a[i]) { j++; }
if (j>0) { return true; }
else { return false; }
}
else if (a[i] === undefined || a[i] === null) { return false; }
}
catch(e) {
if (e.name === "ReferenceError") { return false; }
}
}
return true;
}
For example, this works:
var foo;
isset(foo); // Returns false
foo = "bar";
isset(foo); // Returns true
foo = {};
isset(foo); // Returns false
isset(foo.bar); // Returns false
foo = { bar: "test" };
isset(foo); // Returns true
isset(foo.bar); // Returns true
Here is the problem... if foo is never set to begin with, this happens:
// foo has not been defined yet
isset(foo); // Returns "ReferenceError: foo is not defined"
I thought I could use try/catch/finally to return false if error.name === "ReferenceError" but it isn't working. Where am I going wrong?
Edit:
So the answer below is correct. As I expected, you cannot access an undefined variable or trap it with try/catch/finally (see below for an explanation).
However, here is a not so elegant solution. You have to pass the name of the variable in quotes, then use eval to do the checking. It's ugly, but it works:
// Usage: isset("foo"); // Returns true or false
function isset(a) {
if (a) {
if (eval("!!window."+a)) {
if (eval("typeof "+a+" === 'object'")) { return eval("Object.keys("+a+").length > 0") ? true : false; }
return (eval(a+" === undefined") || eval(a+" === null") || eval(a+" === ''")) ? false : true;
}
else { return false; }
}
else { console.log("Empty value: isset()"); }
}
And just to follow up some more, I cleaned up the original function at the very top. It still has the same problem where if the variable doesn't exist you get a ReferenceError, but this version is much cleaner:
// Usage: isset(foo); // Returns true or false if the variable exists.
function isset(a) {
if (a) {
if (typeof a === "object") { return Object.keys(a).length > 0 ? true : false; }
return (a === undefined || a === null || a === "") ? false : true;
}
else { console.log("Empty value: isset()"); }
}
You just can't do that type of check with a function. In order to pass the variable, it needs to exist, so it will fail before your code can run.
When you call it on the undeclared variable, you're attempting to resolve the value of the identifier in the argument position.
// v----resolve identifier so it can be passed, but resolution fails
isset(foo);
And of course, it doesn't exist, so the ReferenceError is thrown.
JavaScript doesn't have pointers, so there's nothing like a nil pointer that can be passed in its place.
You cannot pass a identifier that hasn't been initialised. You could pass a string, and an object to test, like the following:
function isset(str, obj) {
return obj[str] ? true : false;
}
isset("foo", window); // >>> false
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
How I can write the following without &&?
if(a == 1 && b == 2) { ... }
Can I create a function for the operator?
Create a function to encapsulate your operation:
function compare(a, b, value1, value2) {
if(a === value1) {
if(b === value2) {
return true;
}
}
return false;
}
And you can use it like so:
if(compare(a, b, 1, 2)) {
// Your action..
}
You can do this like
if(a==1){
if(b==2){
JS function
}
}
Both will work the same but if(a==1 && b==2) is a good approach to do exactly the same.
Not sure why you'd want to do this, but you could nest if statements:
if(a == 1){
if(b == 2){
...
}
}
Or you could use a bitwise operator, if you really just need to consider 2 and 1
if(b >> a === 1){
...
}
There are a lot ways to do it, but it really depends on your data.
You could take advantage of prototypal inheritance, and create a constructor with its prototype extended with methods.
function Comparer(a, b) {
if (!(this instanceof Comparer))
return new Comparer(a, b);
this.assign(a, b);
this.compare();
}
Comparer.prototype.result = false;
Comparer.prototype.compare = function() {
this.result = this.a == this.b;
};
Comparer.prototype.assign = function(a, b) {
this.a = a;
this.b = b;
};
Comparer.prototype.and = function(a, b) {
this.assign(a, b);
if (this.result !== false)
this.compare();
return this;
};
Comparer.prototype.or = function(a, b) {
this.assign(a, b);
if (this.result !== true)
this.compare();
return this;
};
And use it like this:
var a = 1,
b = 2;
if (Comparer(a, 1).and(b, 2).result)
console.log("pass");
else
console.log("fail");
We could even extend it to get rid of the if statement.
Comparer.prototype.then = function(fn) {
if (this.result === true)
fn();
return this;
};
Comparer.prototype.otherwise = function(fn) {
if (this.result === false)
fn();
return this;
};
And use it like this:
var a = 1,
b = 2;
Comparer(a, 1)
.and(b, 2)
.then(function() { console.log("pass"); })
.otherwise(function() { console.log("fail"); });
Or shorten things up like this:
var log = Function.bind.bind(console.log, console);
var a = 1,
b = 2;
Comparer(a, 1)
.and(b, 2)
.then(log("pass"))
.otherwise(log("fail"));
Your question is sort of pointless, but you could use the multiplication operator * instead of &&:
if(a==1 * b==2){
//do something
}
If you want to implement the operator && as a function, it's going to get ugly, because you need to pass the conditions as closures, whenever you care about short-circuiting with side-effects.
Example:
if(condition && changeTheWorld()) { ... }
// Cannot be translated into a function call of this nature:
if(land(condition, changeTheWorld()) { ... }
Instead, you would need to create a closure:
if(land(condition, function() {return changeTheWorld()}) {...}
As you can see, it's really cumbersome and verbose while there's no advantage.
If you really need this as a funciton, here is an
Implementation with short-circuiting
This function emulates the semantics of && correctly, if you pass the conditions that must not get evaluated—in the case of short-circuiting—as functions instead as expressions.
In other words, the function goes through the arguments in order, if one is a function, it evaluates it first, otherwise it just takes its value, if falsy, it aborts by returning false, otherwise, it continues with the next parameter.
function land(){
for(var i = 0; i < arguments.length; i++) {
var operand = arguments[i];
var value = (typeof operand === 'function') ? operand() : operand;
if (!value) {
return false;
}
}
return true;
}
Example:
function evaluateTo(result) {
return function() {
console.log("Evaluating " + result);
return result;
};
}
if(land(true, evaluateTo(1))) {
console.log("All truthy");
}
// Outputs:
// Evaluating 1
// All truthy
if(land(evaluateTo(1), evaluateTo(0), evaluateTo(true))) {
console.log("All truthy");
}
// Outputs:
// Evaluating 1
// Evaluating 0
Obligatory missile example
function changeTheWorld() {
console.log("Missiles away!");
// Firing 3 missiles
return nukeTheGlobe(3);
}
if(false && changeTheWorld() == 3) { ... }
// we survived, missiles not fired
if(naiveLand(maybe, changeTheWorld() == 3) { ... }
// Missiles away! no matter what value `maybe` has
if(land(false, function(){ return changeTheWorld() == 3; })) {...}
// we survived, missiles not fired
I need to design a global boolean with 2 conditions a and b such that if A is ever true, the boolean is true until b is true, at which point the boolean is false. In other words, if A becomes false the boolean remains true.
I tried a straightforward global variable but it became false when A became false.
Preferably JavaScript, but pseudocode would be almost as helpful.
This sounds like an XOR. i.e.
!A and !B == false
A and !B == true
!A and B == true
A and B == false
Unfortunately, JavaScript doesn't have a logical XOR operator, however
if( A ? !B : B ) {
is functionally equivalent
If I understand your question correctly, it should be fairly easy to match those cases with
var bool = (a != b);
/*
(false != false) = false
(true != false) = true
(false != true) = true
(true != true) = false
*/
With your changes, you could create a global variable var aWasEverTrue = a; and then instead of setting a directly, use a function such as setA(true).
var a = false;
var b = false;
var aWasEverTrue = a;
function setA(newAValue) {
aWasEverTrue = true;
a = newAValue;
}
// (aWasEverTrue != b) = false
setA(true);
// (aWasEverTrue != b) = true
b = true;
// (aWasEverTrue != b) = false
setA(false);
// (aWasEverTrue != b) = false (as aWasEverTrue is still true)
b = false
// (aWasEverTrue != b) = true
What you want is a state machine
States for result:
T (True)
F (False)
Transitions:
F -- a (true) --> T
F -- anything else --> F
T -- b (true) --> F
T -- anything else --> T
You can express it with a series of ifs
Javascript old-school way:
function Enjoy() {
this.a = true;
this.b = true;
this.bool = true;
}
Enjoy.prototype = {
constructor: Enjoy,
setA: function( val ) {
this.a = val;
if ( this.a === true && this.b === true ) this.bool = false;
else if ( this.a === true && this.b === false ) this.bool = true;
},
setB: function( val ) {
this.b = val;
if ( this.a === true && this.b === true ) this.bool = true;
else if ( this.a === true && this.b === false ) this.bool = false;
},
getBool: function() {
return this.bool;
}
};
var enjoy = new Enjoy();
enjoy.getBool(); // true
enjoy.setB( false );
enjoy.getBool(); // false
As you can see, the idea is to use getters/setters for your boolean and both a and b variables where you do all your logic.
By the way, this question is definitely for StackOverflow.
Based on some assumptions about how B should behave if A has not been true:
function FlipFlop(){
this.latch = false;
this.value = false;
}
FlipFlop.prototype = {
constructor: FlipFlop,
setA: function( val ) {
this.latch = this.latch || !!val;
this.value = this.latch;
},
setB: function( val ) {
if(this.latch && !!val) {
this.latch = false;
}
this.value = !val;
},
getVal: function() {
return this.value;
}
}