Returning from a function returns undefined - javascript

I have a function in a class definition that returns undefined.
Here is the class:
class Lexer {
// constructor and another method here
make_tokens() {
var tokens = [];
// checking character values here
console.log(tokens);
// Outputs [ Token { type: 'PLUS', value: undefined }, Token { type: 'PLUS', value: undefined } ] if I enter ++
return tokens, null; // returns undefined, null
}
// make_numbers() goes here
}
When I searched for answers, I mainly got returning from asynchronous functions but my function is not asynchronous.
I do not know what the problem is.
(sorry if I didn't structure it well but I am new to StackOverflow and I don't know how to structure a question properly)

Firstly, why you want to return null with other variable but if so then just return an array consisting of 2 elements.
Here's is the code:
class Lexer {
// constructor and another method here
make_tokens() {
var tokens = [];
// checking character values here
console.log(tokens);
// Outputs [ Token { type: 'PLUS', value: undefined }, Token { type: 'PLUS', value: undefined } ] if I enter ++
return [tokens, null] ; // returns undefined, null
}
// make_numbers() goes here
}
But it can be the other way. For eg You want to return null if tokens are not present.
class Lexer {
// constructor and another method here
make_tokens() {
var tokens = [];
// checking character values here
console.log(tokens);
// Outputs [ Token { type: 'PLUS', value: undefined }, Token { type: 'PLUS', value: undefined } ] if I enter ++
return tokens | null; // returns undefined, null
}
// make_numbers() goes here
}

i don't think you could return value that way.
class Lexer {
// constructor and another method here
make_tokens() {
var tokens = [];
// checking character values here
console.log(tokens);
// Outputs [ Token { type: 'PLUS', value: undefined }, Token { type: 'PLUS', value: undefined } ] if I enter ++
return [tokens, null]; // returns undefined, null
}
// make_numbers() goes here
}
const lexer = new Lexer();
console.log(lexer.make_tokens());

You can't return multiple values like that.
I think you end up just returning the last value which in this case is null.
Why do you need to return null aswell?
If you just return tokens it will work.

Just return tokens
class Lexer {
// constructor and another method here
make_tokens() {
var tokens = [];
// checking character values here
console.log(tokens);
// Outputs [ Token { type: 'PLUS', value: undefined }, Token { type: 'PLUS', value: undefined } ] if I enter ++
return tokens; // returns tokens
}
// make_numbers() goes here
}
const lexer = new Lexer();
console.log(lexer.make_tokens());

Related

Undefined vs Empty String - Javascript with example

I am trying to find the first processed === true and return the value.
My works seems to work but if there are no processed the code turns undefined instead of <empty string>
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
const myValue = values.reduce((acc, curr) => {
if (curr.primary) {
return curr.value.toLowerCase();
}
}, '');
console.log("My Value: " + myValue);
What am I missing here?
reduce calls the callback function once for each item in the loop.
curr is the current value. acc is the return value from the previous function (or the second argument ('') the first time going around the loop.
Your code completely ignores acc so the value returned by reduce depends entirely on the last value in the array.
Your function tests that value with curr.primary. If that is a true value it return curr.value.toLowerCase(). If it isn't a true value, then it gets to the end of the function without hitting a return statement. Any function that doesn't return will return undefined.
To find the first value that matches a condition, use find not reduce.
Then do a test to use an empty string if you didn't find anything.
const match = values.find(value => value.primary === true);
const myValue = match?.value.toLowerCase() ?? "";
I am trying to find the first processed === true and return the value [else an empty string ""].
You can use Array.prototype.find() with the optional chaining operator (?.) along with the nullish coalescing operator (??) in the case that no value is found:
const array1 = [
{ value: 'bar', processed: false },
{ value: 'foo', processed: false },
];
const myValue1 = array1.find(o => o.processed)?.value.toLowerCase() ?? '';
console.log('myValue1:', myValue1); // "myValue1:" ""
console.log('type:', typeof myValue1); // "type:" "string"
const array2 = [
{ value: 'BAR', processed: false },
{ value: 'FOO', processed: true },
];
const myValue2 = array2.find(o => o.processed)?.value.toLowerCase() ?? '';
console.log('myValue2:', myValue2); // "myValue2:" "foo"
console.log('type:', typeof myValue2); // "type:" "string"
Here's a breakdown of the syntax evaluation for the first value:
const myValue1 = array1.find(o => o.processed)?.value.toLowerCase() ?? '';
// 11111111111111111111111111111 22222222222222222222 44 55
// 33333333333333333333333333333333333333333333333333
// 1. This evaluates to undefined
// 2. So this part is not evaluated, and...
// 3. the entire left side evaluates to undefined
// 4. Because 3 is nullable (null or undefined), when the ?? operator executes...
// 5. the left side (3) is ignored, and the right side (5) becomes the value
In contrast with the value computed from the second array:
const myValue2 = array2.find(o => o.processed)?.value.toLowerCase() ?? '';
// 11111111111111111111111111111 22222233333333333333 55 66
// 44444444444444444444444444444444444444444444444444
// 1. This evaluates to { value: 'FOO', processed: true }
// 2. So this part is evaluated to "FOO"
// 3. which becomes "foo", and...
// 4. the entire left side evaluates to "foo"
// 5. Because 4 is NOT nullable (null or undefined), when the ?? operator executes...
// 6. the left side (4) becomes the final value, and the right side (6) is ignored
To find the first element that meets a condition you should use find method.
Reduce will run on the entire array even after that condition is met since it's purpose is to reduce an entire array into a different data structure (i.e string/object). Find method will exit as soon as an item that meets the condition is found (or after checking the entire array if non of the items does)
As to replacing undefined with an empty string, in the attached snippet I used a or condition (although some would prefer conditional operator), since undefined is falsey, it will insert the empty string.
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
const myValue = values.find(curr => curr.process);
console.log("My Value: " + (myValue?.value?.toLowerCase() || ''));
Best of luck with your project:)
This should be all:
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
const myValue = values.reduce((acc, curr) => curr.process ? curr.value.toLowerCase() : '', '');
console.log("My Value: " + myValue);
you might be better off using a foreach loop to accomplish what you are trying to do:
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
var processedValue = '';
values.forEach(element => {
if(element.process && !processedValue)
processedValue = element.value;
});
console.log(processedValue);

A class of an object that receives data from two other classes of the same object

I want to create an object in which the class uses the data of two other classes of the same object.
const MatchReplace = {
Username: {
RegExp: new RegExp('%USERNAME%', 'g'), // Joined user name
Value: 'DareFox'
},
UserWithTag: {
RegExp: new RegExp('%USERWITHTAG%', 'g'), // User#XXXX
Value: 'DareFox#0100'
},
ServerName: {
RegExp: new RegExp('%SERVERNAME%', 'g'), // Name of this server
Value: 'StackOverflow'
},
MemberCount: {
RegExp: new RegExp('%MEMBERCOUNT%', 'g'), // Member count (human & bots)
Value: '1005'
},
HumanCount: {
RegExp: new RegExp('%HUMANCOUNT%', 'g'), // Only human count
Value: '1000'
},
BotCount: {
RegExp: new RegExp('%BOTCOUNT%', 'g'), // Only bot count
Value: MatchReplace.MemberCount.Value - MatchReplace.HumanCount.Value // Expected: 5
}
}
But I get an error:
Value: MatchReplace.MemberCount.Value - MatchReplace.HumanCount.Value
^
ReferenceError: Cannot access 'MatchReplace' before initialization
Why does this not work and how to make it work?
It doesn't work because when you create the object JS initializes every property and that cant be done since the object is not still initialized and you have a reference to it in one of its properties.
You can proceed in three ways:
Define the values before the object.
Initialize the object and then assign its properties one by one in the right order.
Define the value using a function or a getter:
const matchReplace = {
//...
BotCount: {
RegExp: new RegExp('%BOTCOUNT%', 'g'), // Only bot count
get Value() {return MatchReplace.MemberCount.Value - MatchReplace.HumanCount.Value; } // Expected: 5
}
}

TypeError: map[key].push is not a function

I'm not sure why I'm getting this error as I do have map variable declare in my function:-(
if I run below code :
if (key in map) {
map[key].push(value)
} else {
map[key] = value
}
my output would be like this :
{ url: ['account/43' ],
status: [ '200' ],
headers:
[ 'content-type = application/json',
'content-type = application/text' ],
body: [ '{ name: xyz}' ] }
Instead of that if I run below line of code inside the function :
map[key] = ["headers", "body"].includes(key)? [value] : value
the output would be like below( url/status in string and headers/body in array format) but its not taking multiple value of headers, basically it's replacing the value.
{ url: 'account/43',
status: '200',
headers: [ 'content-type = application/text' ],
body: [ '{ name: xyz }' ] }
I'm trying to achieve kind of both condition( firstly , url.status should be in string format and headers/body should be in array format. secondly headers or body can append/push multiple value like below output:
{url: 'account/43',
status: '200',
headers:
[ 'content-type = application/json',
'content-type = application/text' ],
body: [ '{ name: xyz }' ] }
Here is the actual function
function processFile(content) {
let map = {}
content.forEach(function(node) {
if (node.startsWith("//")) {
key = node.substring(2, node.length-2).toLowerCase().trim()
return
} else {
value = node
}
if (key in map) {
map[key].push(value)
} else {
map[key] = value
}
map[key] = ["headers", "body"].includes(key)? [value] : value
})
return map
}
ERROR
map[key].push(value)
^
TypeError: map[key].push is not a function
This is how you can do it -
function processFile(content) {
let map = {}
content.forEach(function(node) {
if (node.startsWith("//")) {
key = node.substring(2, node.length - 2).toLowerCase().trim()
return
} else {
value = node
}
if (key in map) {
map[key].push(value)
} else {
map[key] = [value];
}
map[key] = ["headers", "body"].includes(key) ? [value] : value
})
return map
}
You've ensured that for headers and body, multiple values are possible. However, based on the error, it's evident that there is a duplicate for some other key as well.
Consider using a function like this:
function processFile(content) {
let key;
return content.reduce(
function (map, node) {
if (node.startsWith('//')) {
key = node.substring(2, node.length-2).toLowerCase().trim();
} else if (key) {
if (map[key]) {
if (map[key].push) {
map[key].push(node);
} else {
throw new Error(`Duplicate key ${key} for scalar value`);
}
} else {
map[key] = node;
}
} else {
throw new Error(`Data encountered without a key: ${node}`);
}
return map;
},
{ headers: [], body: [] }
);
}
This will throw an error when the duplicate key is encountered, giving you a chance to debug it.
Other improvements I made:
Use reduce() instead of forEach().
Initialize the map with an empty array for headers and body, which eliminates the need for a special-case test in your iteration function.
Declared key, which was previously unnecessarily a global.
Data without a previously-seen key causes an error instead of storing the data at map["undefined"].
The method push() belongs to the Array class.
When you do:
map[key] = value
and latter call:
map[key].push(value)
There was no array in map[key]. In order to push an element here we need to store an array in map[key]. To do so, instead of
map[key] = value //element value being stored in map[key]
we need to do something like this:
map[key] = [value] // array containing value in the first position
Initializing and storing the array.

Return property of Object instead of Object itself when using find()

I am trying to get the value of the client using the client's name and for some reason I get back the full client object:
function createBank(clients) {
return {
clients: clients,
safeBoxValue: function() {
return this.clients.reduce(function(sum, client) {
return sum + client.value;
}, 0);
},
getclientValue: function(clientName) {
return this.clients.find(function(client) {
if (client.name === clientName) {
return client.value;
}
});
}
}
}
var clients = [
{name: "John", value: 349},
{name: "Jane", value: 9241},
{name: "Jill", value: 12734},
]
var bank = createBank(clients);
bank.safeBoxValue(); // 22324
bank.getclientValue('Jill'); // {"name":"Jill","value":12734}
Anybody knows why? Thanks!
array.find() works by passing in a function that returns a Boolean value to determine whether the object is the one you're looking for. Your function is working despite the code because you are returning a value that is 'truthy' when you return client.value.
The function would work exactly the same if you had just done this:
getclientValue: function(clientName) {
return this.clients.find(function(client) {
return client.name === clientName
});
}
It will go through the array until you return true and then pass you the element, in this case the whole object, you just found. To only get the value, you will need to return it separately:
getclientValue: function(clientName) {
var found = this.clients.find(function(client) {
return client.name === clientName
});
return found && found.value
}
Just remember find() only returns the first value found.

Partial depth comparison between two objects

The use of JavaScript to achieve the depth of two objects is comapre, if true is not equal to equal returns, returns false. The first parameter compare to the original object, second parameters for the comparison of the target object, the object attribute exists in value only exists, the property does not exist in the original object if the object, it will return directly false. Here are some examples.
const object = {
id: 1,
name: 'test',
product: {
id: 1,
name: 'product'
},
updatedAt: 'now'
};
const objectA = {
name: 'test',
product: {
name: 'product'
}
};
const objectB = {
name: 'test',
product: {
name: 'anotherProduct'
}
};
compare(object, objectA) // return true
compare(object, objectB) // return false
Here is the solution i made,
fiddle - https://jsfiddle.net/jayjoshi64/qn70yosx/5/
it has recursive function which will check if two given object is object or one of implicit object.
if it is object, it will again check recursively if they are same.
code of the function compare..
it is working for your objects.!
function compare(first,second)
{
//alert("once");
var flag=true;
if(typeof second=='object')
{
//if the variable is of type object
if(typeof first!='object')
{
flag=false
}
else
{
//check every key of object
$.each(second, function(key, value) {
//if socond's key is available in first.
if(first.hasOwnProperty(key))
{
//recursive call for the value.
if(!compare(first[key],second[key]))
{
flag=false;
}
}
else
{
flag=false
}
});
}
}
else
{
// if two objects are int,string,float,bool.
if(first!=second)
{
flag=false;
}
}
return(flag);
}

Categories