How to recognize if a string is an object? - javascript

I have to make a program where the user will input the name of an object with prompt() and after that all of the properties of the object will be listed.
Many students in my course are using eval(), but I've read that it's not a good idea to use this method.
So I tried to code something better but I haven't been able to complete it. My biggest problems are when the user writes this.object and when he writes object.object.object and the properties of the third object have to be displayed.
var x = prompt("Object?");
x = x.toLowerCase();
if (x === "window") {
x = window;
load_table();
} else if (window[x]) {
x = window[x];
load_table();
} else if (x[0] === "t" && x[1] === "h" && x[2] === "i" && x[3] === "s" && x[4] === ".") {
x = x.split('.');
x = x[1];
load_table();
} else {
document.write("Error Message.");
}
Any tip?

Try something like this:
var x = prompt("Object?");
// x = x.toLowerCase(); // not including, what if the object has a capital in its name?
x = x.split('.');
if (x[0] == 'this') {
x.shift(); // remove this, as it refers to window anyways
}
var theObj = window; // start with the global object
for (var i = 0; i < x.length; i++) {
theObj = theObj[x[i]];
if (theObj == undefined) break;
}
The variable theObj will contain your final value.

You might want a recursive function with a type checker. Then you might also want to write a function to check if the window objects has an object in it named like the value.
function check(val){
if(!val) return "No value";
else if(typeof val === "string"){
return val;
} else if(typeof val === "object"){
var returner = "{";
for(var i in val){
returner += i + ": ";
returner += check(val[i]);
returner += ",";
}
return returner + "}"
} else {
return "Not object or string";
}
}
function tellMe(string){
if(string.split(".").length >= 2){
var check = window;
var split = string.split(".");
for(var i = 0; i < split.length; i++){
if(typeof check[string[i]] != "undefined"){
check = window[string[i]];
}
}
return "The closest value is " + check;
} else if(typeof window[string] != "undefined"){
return check(window[string]);
} else {
return "Value cannot be found in window object";
}
}
Example
var string = "A string";
var object = {"key1":"value1","key2":"value2"};
console.log(tellMe("string"));
console.log(check(string));
console.log(tellMe("object"));
console.log(check(object));

Related

Can I filter a Matrix or Vector with a string sentence in Google Apps Script?

I'm implementing a Google Script WebApp which will be able to filter a Google Sheet with a few parameters. What is happening is... I have a 30 columns approximately and each column would be a parameter. I thought this:
let MYBOOK = SpreadsheetApp.openById(id);
let SS = MICBOOK.getSheetByName('DATA');
let DATA = SS.getDataRange().getDisplayValues();
let f = null;
if(e.nombre != ''){ // Never null
f += 'index[0] == e.nombre'
}
if(e.ciudad != ''){
f += '&& index[1] == e.ciudad '
}
if(e.tipo != ''){
f += '&& index[2] == e.tipo '
}
let result = DATA.filter(index => {
return f;
})
// And more and more if ...
return result;
But the script result is all matrix and no filter.
Is this what you are trying to accomplish?
let MYBOOK = SpreadsheetApp.openById(id);
let SS = MICBOOK.getSheetByName('DATA');
let DATA = SS.getDataRange().getDisplayValues();
let f = null;
let result = DATA.filter(datum => {
// moved if statements inside this function
if(datum.nombre != ''){ // Never null
f += 'index[0] == e.nombre'
}
if(datum.ciudad != ''){
f += '&& index[1] == e.ciudad '
}
if(datum.tipo != ''){
f += '&& index[2] == e.tipo '
}
return f;
})
// And more and more if ...
return result;
}
I was looking for a solution and i found a similar question. All i need was
eval(string);
To convert a string to a Js Code, so if a put:
data.filter(index => {
return eval(f);
})
Where f = index[0] == e.nombre && index[1] == e.ciudad && index[2] == e.tipo it returns a new Matrix with filters values OK.
Thanks a lot.

How to restore a JSON string from a compressed blob in Google Apps Script?

I need to store a large json into a cell of a spreadsheet. Since there's a 50k character limit I thought of compressing the json string. I've managed to store the compressed blob as a base64 encoded string, but I'm failing to restore it to the original json. When the readLargeJson function is called I get the following error: "Blob object must have non-null content type for this operation".
The insertLargeJson function below seems to be working correctly.
I tried also storing without the base64 encoding, but didn't help.
function insertLargeJson()
{
var obj = {};
obj["dummy"] = [];
// Just to make the json huge
for (var i = 0; i < 10000; i++)
{
obj["dummy"].push("value");
}
var activeSheet = SpreadsheetApp.getActiveSheet();
var str = JSON.stringify(obj);
var blob = Utilities.newBlob(str, 'application/octet-stream');
var compressedBlob = Utilities.zip([blob]);
var encoded = Utilities.base64Encode(compressedBlob.getDataAsString());
activeSheet.getRange(1, 1).setValue(encoded);
}
function readLargeJson()
{
var activeSheet = SpreadsheetApp.getActiveSheet();
var values = activeSheet.getSheetValues(1, 1, 1, 1);
var value = values[0, 0];
var decoded = Utilities.base64Decode(value);
var blob = Utilities.newBlob(decoded);
var unzipped = Utilities.unzip(blob);
var obj = JSON.parse(unzipped.getDataAsString());
Browser.msgBox('Test Json array size', "" + obj["dummy"].length, Browser.Buttons.OK);
}
I don't necessarily need to use the blob interface to compress the json, any solution that would compress the json string and that would be storable in a cell for later retrieving the original json would work.
It is an interesting concept so I search a bit and get something working.
In your code you have to use compressedBlob.getBytes() to encode data and not compressedBlob.getDataAsString(). To create a blob in your read function you must use bytes in input.
Then in your read function the unzip return an array and before to get the data you have to use the getAs() function. So you must have unzipped[0].getAs('application/octet-stream').getDataAsString() and not unzipped.getDataAsString()
I made a single function to ease testing, so you just have to split it depending your need.
function insertReadLargeJson(){
var obj = {};
obj["dummy"] = [];
// Just to make the json huge
for (var i = 0; i < 10000; i++)
{
obj["dummy"].push("value");
}
// Logger.log(obj)
var activeSheet = SpreadsheetApp.getActiveSheet();
var str = JSON.stringify(obj);
var blob = Utilities.newBlob(str, 'application/octet-stream');
var compressedBlob = Utilities.zip([blob]);
var encoded = Utilities.base64Encode(compressedBlob.getBytes());
activeSheet.getRange(1, 1).setValue(encoded);
var decoded = Utilities.base64Decode(encoded);
var blob = Utilities.newBlob(decoded,'application/zip');
var unzipped = Utilities.unzip(blob);
var obj = JSON.parse(unzipped[0].getAs('application/octet-stream').getDataAsString());
// Logger.log(JSON.stringify(obj))
Logger.log(obj.dummy.length)
// Logger.log('Test Json array size', "" + obj["dummy"].length)
}
I was able to do it with the help of an external library.
I converted the code to be readable by Apps Script:
JSONPACK.gs
var TOKEN_TRUE = -1;
var TOKEN_FALSE = -2;
var TOKEN_NULL = -3;
var TOKEN_EMPTY_STRING = -4;
var TOKEN_UNDEFINED = -5;
function pack(json, options) {
// Canonizes the options
options = options || {};
// A shorthand for debugging
var verbose = options.verbose || false;
verbose && console.log('Normalize the JSON Object');
// JSON as Javascript Object (Not string representation)
json = typeof json === 'string' ? this.JSON.parse(json) : json;
verbose && console.log('Creating a empty dictionary');
// The dictionary
var dictionary = {
strings : [],
integers : [],
floats : []
};
verbose && console.log('Creating the AST');
// The AST
var ast = (function recursiveAstBuilder(item) {
verbose && console.log('Calling recursiveAstBuilder with ' + this.JSON.stringify(item));
// The type of the item
var type = typeof item;
// Case 7: The item is null
if (item === null) {
return {
type : 'null',
index : TOKEN_NULL
};
}
//add undefined
if (typeof item === 'undefined') {
return {
type : 'undefined',
index : TOKEN_UNDEFINED
};
}
// Case 1: The item is Array Object
if ( item instanceof Array) {
// Create a new sub-AST of type Array (#)
var ast = ['#'];
// Add each items
for (var i in item) {
if (!item.hasOwnProperty(i)) continue;
ast.push(recursiveAstBuilder(item[i]));
}
// And return
return ast;
}
// Case 2: The item is Object
if (type === 'object') {
// Create a new sub-AST of type Object ($)
var ast = ['$'];
// Add each items
for (var key in item) {
if (!item.hasOwnProperty(key))
continue;
ast.push(recursiveAstBuilder(key));
ast.push(recursiveAstBuilder(item[key]));
}
// And return
return ast;
}
// Case 3: The item empty string
if (item === '') {
return {
type : 'empty',
index : TOKEN_EMPTY_STRING
};
}
// Case 4: The item is String
if (type === 'string') {
// The index of that word in the dictionary
var index = indexOf.call(dictionary.strings, item);
// If not, add to the dictionary and actualize the index
if (index == -1) {
dictionary.strings.push(encode(item));
index = dictionary.strings.length - 1;
}
// Return the token
return {
type : 'strings',
index : index
};
}
// Case 5: The item is integer
if (type === 'number' && item % 1 === 0) {
// The index of that number in the dictionary
var index = indexOf.call(dictionary.integers, item);
// If not, add to the dictionary and actualize the index
if (index == -1) {
dictionary.integers.push(base10To36(item));
index = dictionary.integers.length - 1;
}
// Return the token
return {
type : 'integers',
index : index
};
}
// Case 6: The item is float
if (type === 'number') {
// The index of that number in the dictionary
var index = indexOf.call(dictionary.floats, item);
// If not, add to the dictionary and actualize the index
if (index == -1) {
// Float not use base 36
dictionary.floats.push(item);
index = dictionary.floats.length - 1;
}
// Return the token
return {
type : 'floats',
index : index
};
}
// Case 7: The item is boolean
if (type === 'boolean') {
return {
type : 'boolean',
index : item ? TOKEN_TRUE : TOKEN_FALSE
};
}
// Default
throw new Error('Unexpected argument of type ' + typeof (item));
})(json);
// A set of shorthands proxies for the length of the dictionaries
var stringLength = dictionary.strings.length;
var integerLength = dictionary.integers.length;
var floatLength = dictionary.floats.length;
verbose && console.log('Parsing the dictionary');
// Create a raw dictionary
var packed = dictionary.strings.join('|');
packed += '^' + dictionary.integers.join('|');
packed += '^' + dictionary.floats.join('|');
verbose && console.log('Parsing the structure');
// And add the structure
packed += '^' + (function recursiveParser(item) {
verbose && console.log('Calling a recursiveParser with ' + this.JSON.stringify(item));
// If the item is Array, then is a object of
// type [object Object] or [object Array]
if ( item instanceof Array) {
// The packed resulting
var packed = item.shift();
for (var i in item) {
if (!item.hasOwnProperty(i))
continue;
packed += recursiveParser(item[i]) + '|';
}
return (packed[packed.length - 1] === '|' ? packed.slice(0, -1) : packed) + ']';
}
// A shorthand proxies
var type = item.type, index = item.index;
if (type === 'strings') {
// Just return the base 36 of index
return base10To36(index);
}
if (type === 'integers') {
// Return a base 36 of index plus stringLength offset
return base10To36(stringLength + index);
}
if (type === 'floats') {
// Return a base 36 of index plus stringLength and integerLength offset
return base10To36(stringLength + integerLength + index);
}
if (type === 'boolean') {
return item.index;
}
if (type === 'null') {
return TOKEN_NULL;
}
if (type === 'undefined') {
return TOKEN_UNDEFINED;
}
if (type === 'empty') {
return TOKEN_EMPTY_STRING;
}
throw new TypeError('The item is alien!');
})(ast);
verbose && console.log('Ending parser');
// If debug, return a internal representation of dictionary and stuff
if (options.debug)
return {
dictionary : dictionary,
ast : ast,
packed : packed
};
return packed;
};
function unpack(packed, options) {
// Canonizes the options
options = options || {};
// A raw buffer
var rawBuffers = packed.split('^');
// Create a dictionary
options.verbose && console.log('Building dictionary');
var dictionary = [];
// Add the strings values
var buffer = rawBuffers[0];
if (buffer !== '') {
buffer = buffer.split('|');
options.verbose && console.log('Parse the strings dictionary');
for (var i=0, n=buffer.length; i<n; i++){
dictionary.push((buffer[i]));
}
}
// Add the integers values
buffer = rawBuffers[1];
if (buffer !== '') {
buffer = buffer.split('|');
options.verbose && console.log('Parse the integers dictionary');
for (var i=0, n=buffer.length; i<n; i++){
dictionary.push(base36To10(buffer[i]));
}
}
// Add the floats values
buffer = rawBuffers[2];
if (buffer !== '') {
buffer = buffer.split('|')
options.verbose && console.log('Parse the floats dictionary');
for (var i=0, n=buffer.length; i<n; i++){
dictionary.push(parseFloat(buffer[i]));
}
}
// Free memory
buffer = null;
options.verbose && console.log('Tokenizing the structure');
// Tokenizer the structure
var number36 = '';
var tokens = [];
var len=rawBuffers[3].length;
for (var i = 0; i < len; i++) {
var symbol = rawBuffers[3].charAt(i);
if (symbol === '|' || symbol === '$' || symbol === '#' || symbol === ']') {
if (number36) {
tokens.push(base36To10(number36));
number36 = '';
}
symbol !== '|' && tokens.push(symbol);
} else {
number36 += symbol;
}
}
// A shorthand proxy for tokens.length
var tokensLength = tokens.length;
// The index of the next token to read
var tokensIndex = 0;
options.verbose && console.log('Starting recursive parser');
return (function recursiveUnpackerParser() {
// Maybe '$' (object) or '#' (array)
var type = tokens[tokensIndex++];
options.verbose && console.log('Reading collection type ' + (type === '$' ? 'object' : 'Array'));
// Parse an array
if (type === '#') {
var node = [];
for (; tokensIndex < tokensLength; tokensIndex++) {
var value = tokens[tokensIndex];
options.verbose && console.log('Read ' + value + ' symbol');
if (value === ']')
return node;
if (value === '#' || value === '$') {
node.push(recursiveUnpackerParser());
} else {
switch(value) {
case TOKEN_TRUE:
node.push(true);
break;
case TOKEN_FALSE:
node.push(false);
break;
case TOKEN_NULL:
node.push(null);
break;
case TOKEN_UNDEFINED:
node.push(undefined);
break;
case TOKEN_EMPTY_STRING:
node.push('');
break;
default:
node.push(dictionary[value]);
}
}
}
options.verbose && console.log('Parsed ' + this.JSON.stringify(node));
return node;
}
// Parse a object
if (type === '$') {
var node = {};
for (; tokensIndex < tokensLength; tokensIndex++) {
var key = tokens[tokensIndex];
if (key === ']')
return node;
if (key === TOKEN_EMPTY_STRING)
key = '';
else
key = dictionary[key];
var value = tokens[++tokensIndex];
if (value === '#' || value === '$') {
node[key] = recursiveUnpackerParser();
} else {
switch(value) {
case TOKEN_TRUE:
node[key] = true;
break;
case TOKEN_FALSE:
node[key] = false;
break;
case TOKEN_NULL:
node[key] = null;
break;
case TOKEN_UNDEFINED:
node[key] = undefined;
break;
case TOKEN_EMPTY_STRING:
node[key] = '';
break;
default:
node[key] = dictionary[value];
}
}
}
options.verbose && console.log('Parsed ' + this.JSON.stringify(node));
return node;
}
throw new TypeError('Bad token ' + type + ' isn\'t a type');
})();
}
function indexOfDictionary (dictionary, value) {
// The type of the value
var type = typeof value;
// If is boolean, return a boolean token
if (type === 'boolean')
return value ? TOKEN_TRUE : TOKEN_FALSE;
// If is null, return a... yes! the null token
if (value === null)
return TOKEN_NULL;
//add undefined
if (typeof value === 'undefined')
return TOKEN_UNDEFINED;
if (value === '') {
return TOKEN_EMPTY_STRING;
}
if (type === 'string') {
value = encode(value);
var index = indexOf.call(dictionary.strings, value);
if (index === -1) {
dictionary.strings.push(value);
index = dictionary.strings.length - 1;
}
}
// If has an invalid JSON type (example a function)
if (type !== 'string' && type !== 'number') {
throw new Error('The type is not a JSON type');
};
if (type === 'string') {// string
value = encode(value);
} else if (value % 1 === 0) {// integer
value = base10To36(value);
} else {// float
}
// If is number, "serialize" the value
value = type === 'number' ? base10To36(value) : encode(value);
// Retrieve the index of that value in the dictionary
var index = indexOf.call(dictionary[type], value);
// If that value is not in the dictionary
if (index === -1) {
// Push the value
dictionary[type].push(value);
// And return their index
index = dictionary[type].length - 1;
}
// If the type is a number, then add the '+' prefix character
// to differentiate that they is a number index. If not, then
// just return a 36-based representation of the index
return type === 'number' ? '+' + index : index;
};
function encode(str) {
if ( typeof str !== 'string')
return str;
return str.replace(/[\+ \|\^\%]/g, function(a) {
return ({
' ' : '+',
'+' : '%2B',
'|' : '%7C',
'^' : '%5E',
'%' : '%25'
})[a]
});
};
function decode(str) {
if ( typeof str !== 'string')
return str;
return str.replace(/\+|%2B|%7C|%5E|%25/g, function(a) {
return ({
'+' : ' ',
'%2B' : '+',
'%7C' : '|',
'%5E' : '^',
'%25' : '%'
})[a]
})
};
function base10To36(number) {
return Number.prototype.toString.call(number, 36).toUpperCase();
};
function base36To10(number) {
return parseInt(number, 36);
};
function indexOf(obj, start) {
for (var i = (start || 0), j = this.length; i < j; i++) {
if (this[i] === obj) {
return i;
}
}
return -1;
};
With that, your script can now be:
Code.gs
function insertLargeJson()
{
var obj = {};
obj["dummy"] = [];
// Just to make the json huge
for (var i = 0; i < 10000; i++)
{
obj["dummy"].push("value");
}
var activeSheet = SpreadsheetApp.getActiveSheet();
var packed = pack(obj);
var value = JSON.stringify(packed);
activeSheet.getRange(1, 1).setValue(value);
}
function readLargeJson()
{
var activeSheet = SpreadsheetApp.getActiveSheet();
var value = activeSheet.getRange(1,1).getValue();
var packed = JSON.parse(value);
var obj = unpack(packed);
Browser.msgBox('Test Json array size', "" + obj["dummy"].length, Browser.Buttons.OK);
}
Hope this helps!

javascript always return false in my case

I am writing code for recursion. And here is my code.
Here, what I am trying to do is, if string has ' then replace it with HTML quotes and calling function recursively until all ' have been replaced.
But this is always returning me false. When I alert var a. If I not use return false then it returns undefined. Any clue what is the wrong here?
var a = replaceqt(" hello's there 'how are you?' ");
console.log(a);
function replaceqt(object) {
var indexc = object.indexOf("'");
var next = object.charAt(indexc + 1);
var prev = object.charAt(indexc - 1);
if (indexc == 0) {
object = object.replace("'", "‘");
} else if (parseInt(prev) >= parseInt(0) && parseInt(prev) <= parseInt(9)) {
object = object.replace("'", "'");
} else if (next == " ") {
object = object.replace("'", "’");
} else if (prev == " ") {
object = object.replace("'", "‘");
} else {
object = object.replace("'", "’");
}
indexc = object.indexOf("'");
if (indexc > -1) {
replaceqt(object);
return false;
} else {
return object;
}
}
Because you are returning false whenever there is a second call. Should return the result of recursive invocation instead.
var a = replaceqt(" hello's there 'how are you?' ");
console.log(a);
function replaceqt(object) {
var indexc = object.indexOf("'");
var next = object.charAt(indexc + 1);
var prev = object.charAt(indexc - 1);
if (indexc == 0) {
object = object.replace("'", "‘");
} else if (parseInt(prev) >= parseInt(0) && parseInt(prev) <= parseInt(9)) {
object = object.replace("'", "'");
} else if (next == " ") {
object = object.replace("'", "’");
} else if (prev == " ") {
object = object.replace("'", "‘");
} else {
object = object.replace("'", "’");
}
indexc = object.indexOf("'");
if (indexc <= -1) {
return object;
}
return replaceqt(object);
}
BTW you don't need parseInt(num) if num is a number say 0 or 9.
You need to replace
if (indexc <= -1){
return object;
}else{
replaceqt(object); return false;
}
with
if (indexc <= -1){
return object;
}else{
return replaceqt(object);
}
In your original code, the return value of replaceqt(object) is discarded when indexc >= 0.
You should try using .split and .join functions to simplify your code.
For a simple find-replace all, you can do this:
var sentence = "I hate spaces."
var charToFind = " ";
var replacement = "-";
var afterSplit = sentence.split(charToFind) // ["I", "hate", "spaces"]
var result = afterSplit.join(replacement) // "I-hate-spaces"
Your example is more complex than a find replace, because you need to keep track of left and right quotes.
To get around that, we can figure out if it's even or odd using the index in the array.
var someString = "My 'name' is 'Ryan'... I 'think'."
function replaceQuotesFor (str) {
return str
.split("'")
.map(function (str, index) {
var quote = index % 2 === 1
? '‘'
: '’'
return (index === 0)
? str
: quote + str
})
.join('')
}
console.log('Before:', someString)
console.log('After:', replaceQuotesFor(someString))
I stopped using for loops and modifying indices, because it made debugging frustrating.
I hope these functions help simplify your code and help you in the future!

.toUpperCase() is not a function

When name is all uppercase, then the function should shout back to the user. For example, when name is "JERRY" then the function should return the string "HELLO, JERRY!" The console logs error: .toUpperCase() is not a function.
var hello = "Hello, ";
function greet(name) {
if (name == null) {
console.log(hello + "my friend")
} else if (name == name.toUpperCase()) {
console.log(hello.toUpperCase() + name.toUpperCase())
} else {
console.log(hello + name);
}
}
var names = ["jack", "john"]
greet(names);
names is an array. An array has no such function.
You probably want to call the greet function on every element of the array:
names.forEach(greet);
If you want the greet function to accept an array as argument then you could do
function greet(name) {
if (Array.isArray(name)) {
name.forEach(greet);
return;
}
...
but this kind of polymorphism is usually seen as a bad practice.
You could apply .toString() first, and then use .toUpperCase():
if (name == name.toString().toUpperCase())
names are array declaration so can't use that type of function, if you want print that array using for loop or using names[1] type
<script>
var hello = "Hello, ";
function greet(name) {
if (name == null) {
document.write(hello + "my friend")
} else if (name == name.toUpperCase()) {
document.write(hello.toUpperCase() + name.toUpperCase())
} else {
document.write(hello + name);
}
}
var names = ["jack", "john"]
greet(names[0]);
greet(names[1]);
</script>
var hello = "Hello, ";
function greet(names) {
for (var i = 0; i < names.length; i++) {
var name = names[i];
if (name == null) {
console.log(hello + "my friend")
} else if (name) {
console.log('toUpperCase works: ',hello.toUpperCase() + name.toUpperCase())
} else {
console.log(hello + name);
}
}
}
var names = ["jack", "john"]
greet(names);
If you pass an array into the function, it doesn't work. It's Better now.
Since name is an array, I think you have to loop it first to get the value inside array. Or perhaps you can try my code:
var hello = "Hello, ";
function greet(name) {
//loop name with for of
for (let val of name) {
if (val == null) {
console.log(hello + "my friend")
} else if (val == val.toUpperCase()) {
console.log(hello.toUpperCase() + val.toUpperCase())
} else {
console.log(hello + val);
}
}
}
var names = ["jack", "john"]
greet(names);
Another way, more ES leaning, with error and type handling:
function greet(names) {
const hello = "Hello"
if (!names){
console.log(`${hello} my friend`)
return;
}
// Handles a String
if (typeof names === "string") {
console.log(`${hello} ${name}`)
return;
}
// Error Handling for Array
if (Array.isArray(names) && !names.length) {
console.error("Passed Array is empty")
return;
}
names.map((name) => {
const str = `${hello} ${name}`
name == name.toUpperCase()
? console.log(str.toUpperCase())
: console.log(str)
// Optional if you have toProperCase as a prototype
// : console.log(`${hello} ${name.toProperCase()}`)
})
}
let names = ["jack", "JOHN"]
greet(names)
Results
This will handle an empty array, an array, a string and empty or falsy calls. If you had a need to also handle an Object, it could be done as well with additional code.
Bonus Material
Avoiding a discussion on if using prototypes this way is good or bad,
just showing a reasonable way it could be done if desired.
toProperCase prototype:
String.prototype.toProperCase =
String.prototype.toProperCase ||
function (word) {
if (!word) {
word = this
}
if (word) {
let str = word.toLowerCase().split(" ")
for (let i = 0; i < str.length; i++) {
str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1)
}
return str.join(" ")
} else {
// ERROR message
// RETURNS var passed to it. If there is an issue it just returns the same value.
console.log(
"The util function toProperCase() \nis not able to do anything with '" +
word +
"' a typeof",
typeof word,
"\nReturning variable in same state."
)
return word
}
}

Javascript program keeps outputting wrong index of array

I'm trying to finish an assignment, I'm stuck at and can't find a solution.
Below is my full code.
//Student Object
var student = {
f_name: "",
l_name: "",
s_numb: "",
email: "",
courses: [],
/*This function returns if current object has a specific course
and returns true if it does and false if not.*/
hasCourse: function (course) {
for (var c = 0; c < this.courses.length; c++) {
if (course == this.courses[c]) {
return true;
}
}
return false;
}
};
/*This function returns name with first letter
capitalized and the rest lowercase.*/
function formatingName(name) {
return name.charAt(0).toUpperCase() + name.substr(1, name.length);
}
/*This function validates to match the Student ID pattern and
returns true it matches and false if not.*/
function validateStudentID(sid) {
var patt = /^([0-9]{3}[.]){2}[0-9]{3}$/;
return patt.test(sid);
}
/*This function receives a string array of course codes which
are to be registered for a student. The function returns an empty
string indicating all course codes in the array are valid; otherwise
the function returns the first invalid course code in the array.*/
function validateCourses(courses) {
var error = false;
for (i = 0; i < courses.length; i++) {
if (error == false) {
if (courses[i] != "APC100" && courses[i] != "IPC144" &&
courses[i] != "ULI101" && courses[i] != "IOS110" &&
courses[i] != "EAC150" && courses[i] != "IBC233" &&
courses[i] != "OOP244" && courses[i] != "DBS201" &&
courses[i] != "INT222") {
error = courses[i];
break;
}
}
}
if (error != false) {return error;} else {return "";}
return '';
}
var response = true; //Continues to prompt if error is true
var error = false; //Error flag
var temp_obj = []; //Temporary object that hold current object's values
var temp_course = [];
var students = [];
var x = 0;
while (response == true) {
do {
var str = prompt("Please enter first name, last name, student ID,\nemail and courses (separated by ',')");
if (str == "" || str === null) {
response = false;
break;
}
//Removing white spaces in the string
str = str.split(' ').join('');
//Splitting the string into array by , (coma) and assigning it to temporary object array
temp_obj = str.split(',');
//Validating Student ID
if (validateStudentID(temp_obj[2]) == false) {
alert(temp_obj[2] + " is not a valid student ID, Please use xxx.xxx.xxx format.\nPlease try again!");
error = true;
}
//Validating if student is registered in atleast 1 course.
if (temp_obj.length < 5) {
alert("A student must be registered in at-least 1 course");
error = true;
}
//Checking if student is registered in more than 6 courses
if (temp_obj.length > 10) {
temp_obj = temp_obj.slice(0,9);
}
//Extracting courses from temporary object array
temp_course = temp_obj.slice(4, temp_obj.length);
//Makking all the courses uppercase
for (i = 0; i < temp_course.length; i++) {
temp_course[i] = temp_course[i].toUpperCase();
}
//Validating if courses are valid
if (validateCourses(temp_course) != "") {
alert(validateCourses(temp_course) + " is not the course provided by CPD program!\nPlease try again.");
error = true;
}
}
while (error == true);
//Break out of loop if user submitted nothing or if user pressed cancel
if (response == false) {break;}
//Merging cources array back with temporary object array
temp_obj = temp_obj.concat(temp_course);
//Creating a new instance of a student
students[x] = Object.create(student);
//Assigning values to student object from temporary object;
students[x].f_name = formatingName(temp_obj[0]); //Formatting name
students[x].l_name = formatingName(temp_obj[1]);
students[x].s_numb = temp_obj[2];
students[x].email = temp_obj[3].toLowerCase(); //Making the email all lowercase
//Making the course codes in Uppercase
for (i = 0; i < (temp_obj.length) - 4; i++ ) {
students[x].courses[i] = temp_obj[i + 4].toUpperCase();
}
x++;
}
//Printing total registered students
alert("There are total " + students.length + " students registered.");
var R_fname = [];
var R_lname = [];
var R_sid = [];
var R_email = [];
do {
var no_error = false;
var query = true;
var query_course = [];
while (no_error == false) {
query = prompt("Please enter a course code:");
if (query == "" || query == null) {
query = false;
break;
}
no_error = true;
query_course[0] = query.toUpperCase();
if (validateCourses(query_course) != "") {
alert(query + " is not the course provided by CPD program!\nPlease try again");
no_error = false;
}
}
if (query == false) {break;}
//THIS IS WHERE I THINK THE PROBLEM IS
//THIS IS WHERE I THINK THE PROBLEM IS
//THIS IS WHERE I THINK THE PROBLEM IS
//THIS IS WHERE I THINK THE PROBLEM IS
for (var a = 0; a < students.length; a++) {
//Checking if student is registred in a course
if (students[a].hasCourse(query_course) == true) {
//Assigning values to temporary array.
R_fname[a] = students[a].f_name;
R_lname[a] = students[a].l_name;
R_sid[a] = students[a].s_numb;
R_email[a] = students[a].email;
}
}
var fin_str = "";
//Concatenating all the students in a specific course to fin_str as string.
for (var b = 0; b < R_fname.length; b++) {
fin_str += (R_fname[b] + " " + R_lname[b] + " " + R_sid[b] + " " + R_email[b] + " \n");
}
//Printing list of student in a specific course
alert("List of students registered in " + query + "\n\n" + fin_str);
//Retting temporary arrays
R_fname.length = 0;
R_lname.length = 0;
R_sid.length = 0;
R_email.length = 0;
//Confirms to Exit the query loop
if (confirm("Click 'OK' to continue to query class lists.\nClick 'Cancel' to stop the program.") == false) {break;}
}
while (query != false);
These are the test values:
roy,bean,056.171.486,rbean#example.ca,int222
carl,bell,121.126.536,cbell#example.ca,dbs201,int222
eric,brand,046.123.976,ebrand#example.ca,oop244,dbs201,int222
henry, clay, 034.146.412, hclay#example.ca , ibc233 , oop244 , dbs201 , int222
When the program asks to enter the course code; it is suppose to see if the students have that course and only if they do, it prints that students info.
In my case, even if student does not have the course it still prints it.
Please run the code to see if it makes more sense... I can't explain any better
The problem can be reduced to this:
var Foo = {
courses: []
};
var x = Object.create(Foo);
var y = Object.create(Foo);
x.courses.push(123);
alert(y.courses[0]); // "123"
The reason for this behaviour is that both objects inherit the same prototype and any changes made to .courses will apply to both objects.
For this reason, it would be better to create a constructor function instead:
function Foo()
{
this.courses = [];
}
var x = new Foo();

Categories